Người nhận không đăng ký lỗi ngoại lệ?


112

Trong bảng điều khiển dành cho nhà phát triển của tôi, mọi người tiếp tục báo cáo lỗi mà tôi không thể tái tạo trên bất kỳ điện thoại nào mà tôi có. Một người đã để lại tin nhắn nói rằng anh ta nhận được nó khi họ cố gắng mở màn hình cài đặt của dịch vụ pin của tôi. Như bạn có thể thấy từ lỗi nó cho biết rằng người nhận chưa được đăng ký.

java.lang.RuntimeException: Unable to stop service .BatteryService@4616d688:  java.lang.IllegalArgumentException: Receiver not registered: com.app.notifyme.BatteryService$BatteryNotifyReceiver@4616d9d0
at android.app.ActivityThread.handleStopService(ActivityThread.java:3164)
at android.app.ActivityThread.access$3900(ActivityThread.java:129)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2173)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:143)
at android.app.ActivityThread.main(ActivityThread.java:4701)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalArgumentException: Receiver not registered:com..BatteryService$BatteryNotifyReceiver@4616d9d0
at android.app.ActivityThread$PackageInfo.forgetReceiverDispatcher(ActivityThread.java:805)
at android.app.ContextImpl.unregisterReceiver(ContextImpl.java:859)
at android.content.ContextWrapper.unregisterReceiver(ContextWrapper.java:331)
at com.app.notifyme.BatteryService.onDestroy(BatteryService.java:128)
at android.app.ActivityThread.handleStopService(ActivityThread.java:3150)

Tôi đăng ký là trong onCreate của tôi

@Override
public void onCreate(){
    super.onCreate();
    SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
    IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
    filter.addAction(Intent.ACTION_POWER_CONNECTED);
    filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
    registerReceiver(batteryNotifyReceiver,filter);
    pref.registerOnSharedPreferenceChangeListener(this);
}

Hủy đăng ký onDestroy và cả với trình nghe tùy chọn

    @Override
public void onDestroy(){
    super.onDestroy();
    unregisterReceiver(batteryNotifyReceiver);

}

và đây là bộ thu của tôi trong dịch vụ

private final class BatteryNotifyReceiver extends BroadcastReceiver {

    boolean connected;
    @Override
    public void onReceive(Context context, Intent intent) {

        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 
        SharedPreferences.Editor edit = prefs.edit();

            updatePreferences(prefs);

        level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);



        if(intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)){
            connected = true;
        }else if(intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)){
            connected = false;
        }else if(intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)){

                if(level < lastLevel){
                    if(level > 40){
                        edit.putBoolean("first", false).commit();
                        edit.putBoolean("second", false).commit();
                        edit.putBoolean("third", false).commit();
                       edit.putBoolean("fourth",false).commit();                            
                        edit.putBoolean("fifth", false).commit();
                    }
                    if(level == 40){
                        if(!first){
                        notification(context,battColor,battBlink,battVib,battSound);

                        edit.putBoolean("first", true).commit();
                        }
                    }else if(level == 30){
                        if(!second){
                        notification(context,battColor,battBlink,battVib,battSound);

                        edit.putBoolean("second", true).commit();
                        }
                    }else if(level == 20){
                        if(!third){
                        notification(context,battColor,battBlink,battVib,battSound);

                        edit.putBoolean("third", true).commit();
                        }
                    }else if(level == 15){
                        if(!fourth){
                        notification(context,battColor,battBlink,battVib,battSound);

                        edit.putBoolean("fourth", true).commit();
                        }
                    }else if(level == 5){
                        if(!fifth){
                        notification(context,battColor,battBlink,battVib,battSound);

                        edit.putBoolean("fifth", true).commit();
                        }
                    }
                lastLevel = temp;
            }
        }           

        Intent i = new Intent(context,BatteryNotifyReceiver.class);
        context.startService(i);
    }       
}

bất kỳ ý tưởng tại sao họ sẽ nhận được lỗi đó?

Câu trả lời:


207

Gốc của vấn đề của bạn nằm ở đây:

 unregisterReceiver(batteryNotifyReceiver);

Nếu người nhận đã không được đăng ký (có thể là trong mã mà bạn không đưa vào bài đăng này) hoặc chưa được đăng ký, thì hãy gọi để unregisterReceiverném IllegalArgumentException. Trong trường hợp của bạn, bạn chỉ cần đặt thử / bắt đặc biệt cho ngoại lệ này và bỏ qua nó (giả sử bạn không thể hoặc không muốn kiểm soát số lần bạn gọi unregisterReceivertrên cùng một người gọi).


31
Bản thân nền tảng Android có thể làm được điều này không? Tôi đã có mã tương tự như ở trên, nhưng không có mã nào khác sẽ hủy đăng ký dịch vụ và tôi nhận được cùng một ngoại lệ.
Electrichead

2
Tôi có vấn đề @electrichead cùng, tôi không thể nhìn thấy nơi người nhận sẽ được đăng ký số trước onDestroy () trừ khi Android được làm việc đó đối với tôi ở đâu đó ....
user1088166

@ user1088166, hãy thử ghi đè phương thức onStop () cho hoạt động của bạn. Trong đó thêm một catch (IllegalArgumentException e) và cố unregister phát sóng của bạn - xem giúp (chỉ nhận thấy đây là một bình luận cũ 3 năm :))
Nactus

Trong trường hợp của tôi, thủ phạm là khởi tạo lười biếng - tôi đã bỏ qua đăng ký vì đối tượng không được khởi tạo, vì vậy nó được khởi tạo sau đó và tôi quên đăng ký người nhận.
Boris Treukhov

@electrichead không, nó không làm điều đó cho bạn, bạn chỉ cần chọn phương pháp đúng: LocalBroadcastManager.getInstance(context).unregisterReceiver()hoặccontext.unregisterReceiver()
user924

25

Hãy cẩn thận, khi bạn đăng ký bằng

LocalBroadcastManager.getInstance(this).registerReceiver()

bạn không thể hủy đăng ký bởi

 unregisterReceiver()

bạn phải dùng

LocalBroadcastManager.getInstance(this).unregisterReceiver()

hoặc ứng dụng sẽ bị lỗi, hãy ghi lại như sau:

09-30 14: 00: 55.458 19064-19064 / com.jialan.guangdian.view E / AndroidRuntime: FATAL EXCEPTION: main Process: com.jialan.guangdian.view, PID: 19064 java.lang.Runtime Ngoại lệ: Không thể dừng dịch vụ com.google.android.exoplayer.demo.player.PlayService@141ba331: java.lang.IllegalArgumentException: Người nhận chưa được đăng ký: com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584 tại android.app.ActivityThread. handleStopService (ActivityThread.java:2941) tại android.app.ActivityThread.access $ 2200 (ActivityThread.java:148) tại android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1395) tại android.os.Handler.dispatchMessage (Handler.java:102) tại android.os.Looper.loop (Looper.java:135) tại android.app.ActivityThread.main (ActivityThread.java:5310) tại java.lang.reflect.Method.invoke (Native Method) tại java.lang.reflect.Method.invoke (Method.java:372) tại com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:901) tại com.android.internal.os.ZygoteInit.main (ZygoteInit.java:696) Do: java.lang.IllegalArgument : Người nhận chưa được đăng ký: com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584 tại android.app.LoadedApk.forgetReceiverDispatcher (LoadedApk.java:769) tại android.app.ContextImpl.unregisterReceiver (ContextImpl.unregisterReceiver1794) tại android.content.ContextWrapper.unregisterReceiver (ContextWrapper.java:510) tại com.google.android.exoplayer.demo.player.PlayService.onDestroy (PlayService.java:542) tại android.app.ActivityThread.handleStopService (ActivityThread .java: 2924) tại android.app.ActivityThread.access $ 2200 (ActivityThread.java:148) tại android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1395) tại android.os.Handler.dispatchMessage (Handler.java:102) tại android.os.Looper.loop (Looper.java:135) tại android.app.ActivityThread.main (ActivityThread.java:5310) tại java. lang.reflect.Method.invoke (Native Method) tại java.lang.reflect.Method.invoke (Method.java:372) tại com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:901) tại com.android.internal.os.ZygoteInit.main (ZygoteInit.java:696) 


Đây là một câu trả lời thực sự cho vấn đề này! Chỉ cần đừng quên nếu bạn đăng ký một máy thu toàn cầu hay địa phương trước
user924

23

Sử dụng mã này ở mọi nơi để hủy đăng kýReceiver:

if (batteryNotifyReceiver != null) {
    unregisterReceiver(batteryNotifyReceiver);
    batteryNotifyReceiver = null;
}

6
Vẫn xảy ra với tôi. Tốt hơn hãy sử dụng try-catch.
palindrom

2
Hãy thử tuyên bố nắm bắt thì tốt hơn
Rowland Mtetezi

16

Như đã đề cập trong các câu trả lời khác, ngoại lệ đang được ném ra vì mỗi lệnh gọi đến registerReceiverkhông được khớp với chính xác một lệnh gọi tới unregisterReceiver. Tại sao không?

ActivityKhông phải lúc nào An cũng có một onDestroycuộc gọi phù hợp cho mọi onCreatecuộc gọi. Nếu hệ thống hết bộ nhớ, ứng dụng của bạn sẽ bị loại bỏ mà không gọi được onDestroy.

Vị trí chính xác để thực hiện registerReceivercuộc gọi là trong onResumecuộc gọi và unregisterReceivervào onPause. Cặp cuộc gọi này luôn luôn khớp. Xem biểu đồ vòng đời Hoạt động để biết thêm chi tiết. http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle

Mã của bạn sẽ thay đổi thành:

SharedPreferences mPref
IntentFilter mFilter;

@Override
public void onCreate(){
    super.onCreate();
    mPref = PreferenceManager.getDefaultSharedPreferences(this);
    mFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
    filter.addAction(Intent.ACTION_POWER_CONNECTED);
    filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
 }

@Override
public void onResume() {
    registerReceiver(batteryNotifyReceiver,mFilter);
    mPref.registerOnSharedPreferenceChangeListener(this);
}

@Override
public void onPause(){
     unregisterReceiver(batteryNotifyReceiver, mFilter);
     mPref.unregisterOnSharedPreferenceChangeListener(this);
}

Nhưng điều này sẽ gây ra chi phí đăng ký và hủy đăng ký nhiều lần hơn. Tôi không chắc về số tiền chi phí, nhưng chắc chắn sẽ có một số.
Aman Deep Gautam,

2
Bạn có thực sự đề nghị để lại một ngoại lệ ném trình xử lý không hợp lệ vì nó sẽ tốn một số chu kỳ CPU để loại bỏ nó không?
Curmudgeonlybumbly

11

CHỈNH SỬA: Đây là câu trả lời cho inazaruk và Electrichead ... Tôi đã gặp phải một vấn đề tương tự với họ và phát hiện ra những điều sau đây ...

Có một lỗi lâu dài cho sự cố này ở đây: http://code.google.com/p/android/issues/detail?id=6191

Có vẻ như nó đã bắt đầu từ Android 2.1 và đã có mặt trong tất cả các bản phát hành Android 2.x kể từ đó. Tuy nhiên, tôi không chắc liệu nó có còn là sự cố trong Android 3.x hoặc 4.x hay không.

Dù sao, bài đăng StackOverflow này giải thích cách giải quyết vấn đề một cách chính xác (URL trông không liên quan nhưng tôi hứa là như vậy)

Tại sao trượt bàn phím làm hỏng ứng dụng của tôi?


8

Tôi đã sử dụng khối try-catch để giải quyết vấn đề tạm thời.

// Unregister Observer - Stop monitoring the underlying data source.
        if (mDataSetChangeObserver != null) {
            // Sometimes the Fragment onDestroy() unregisters the observer before calling below code
            // See <a>http://stackoverflow.com/questions/6165070/receiver-not-registered-exception-error</a>
            try  {
                getContext().unregisterReceiver(mDataSetChangeObserver);
                mDataSetChangeObserver = null;
            }
            catch (IllegalArgumentException e) {
                // Check wether we are in debug mode
                if (BuildConfig.IS_DEBUG_MODE) {
                    e.printStackTrace();
                }
            }
        }

3

Khai báo bộ nhận là null và sau đó Đưa các phương thức đăng ký và hủy đăng ký vào onResume () và onPause () của hoạt động tương ứng.

@Override
protected void onResume() {
    super.onResume();
    if (receiver == null) {
        filter = new IntentFilter(ResponseReceiver.ACTION_RESP);
        filter.addCategory(Intent.CATEGORY_DEFAULT);
        receiver = new ResponseReceiver();
        registerReceiver(receiver, filter);
    }
}      

@Override
protected void onPause() {
    super.onPause();
    if (receiver != null) {
        unregisterReceiver(receiver);
        receiver = null;
    }
}

0

Khi thành phần giao diện người dùng đăng ký BR bị hủy, BR cũng vậy. Do đó, khi mã được hủy đăng ký, BR có thể đã bị hủy.


0

Đối với bất kỳ ai gặp phải vấn đề này và họ đã thử tất cả những gì được đề xuất và không có gì vẫn hoạt động, đây là cách tôi sắp xếp vấn đề của mình, thay vì thực hiện, LocalBroadcastManager.getInstance(this).registerReceiver(...) trước tiên tôi tạo một biến cục bộ kiểu LocalBroadcastManager,

private LocalBroadcastManager lbman;

Và đã sử dụng biến này để thực hiện đăng ký và hủy đăng ký trên bộ thu phát sóng, tức là

lbman.registerReceiver(bReceiver);

lbman.unregisterReceiver(bReceiver);

0

Giả sử của bạn broadcastReceiverđược định nghĩa như thế này:

private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {

        // your code

    }
};

Nếu bạn đang sử dụng LocalBroadcasttrong một Hoạt động, thì đây là cách bạn sẽ hủy đăng ký:

LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);

Nếu bạn đang sử dụng LocalBroadcasttrong Fragment, thì đây là cách bạn sẽ hủy đăng ký:

LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(broadcastReceiver);

Nếu bạn đang sử dụng chương trình phát bình thường trong một Hoạt động, thì đây là cách bạn sẽ hủy đăng ký:

unregisterReceiver(broadcastReceiver);

Nếu bạn đang sử dụng chương trình truyền phát bình thường trong Fragment, thì đây là cách bạn sẽ hủy đăng ký:

getActivity().unregisterReceiver(broadcastReceiver);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.