接收器未注册异常错误?


112

在我的开发人员控制台中,人们不断报告错误,我无法在拥有的任何电话上重现该错误。一个人留下一条消息说,当他们尝试打开我的电池服务的设置屏幕时得到了它。从错误中可以看到,它表明接收器未注册。

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)

我注册在我的onCreate中

@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);
}

在onDestroy和首选项监听器中注销

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

}

这是我在服务中的接收者

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);
    }       
}

知道为什么他们会收到该错误吗?

Answers:


207

问题的根源位于:

 unregisterReceiver(batteryNotifyReceiver);

如果接收者已经取消注册(可能是您未在本文中包含的代码中)或未注册,则调用unregisterReceiverthrows IllegalArgumentException。在您的情况下,您只需要对此异常放入特殊的try / catch并忽略它(假设您不能或不希望控制unregisterReceiver在同一Recevier上调用的次数)。


31
Android平台本身可以做到这一点吗?我有与上面类似的代码,但是根本没有其他代码可以取消注册该服务,并且得到了相同的异常。
电动头

2
我有同样的问题@electrichead,除非Android正在某处为我做准备,否则在onDestroy()之前我看不到接收器将在哪里注销。–
user1088166 2013年

@ user1088166,尝试覆盖您的活动的onStop()方法。在其中添加一个try catch(IllegalArgumentException e)并有意取消注册您的广播-看看是否有帮助(只是注意到这是3年的评论了:))
Nactus

在我的案例中,罪魁祸首是延迟初始化-由于对象未初始化,因此我跳过了注册,因此稍后对其进行了初始化,并且我忘记了接收者注册。
鲍里斯·特鲁霍夫

@electrichead不,它对您没有帮助,您只需要选择正确的方法即可:LocalBroadcastManager.getInstance(context).unregisterReceiver()context.unregisterReceiver()
user924 '19

25

当您注册时要小心

LocalBroadcastManager.getInstance(this).registerReceiver()

您不能通过以下方式取消注册

 unregisterReceiver()

你必须使用

LocalBroadcastManager.getInstance(this).unregisterReceiver()

或应用程序将崩溃,请按以下方式记录:

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.RuntimeException:无法停止服务com.google.android.exoplayer.demo.player.PlayService@141ba331:java.lang.IllegalArgumentException:接收者未注册:com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584,位于android.app.ActivityThread。在android.app.ActivityThread.access $ 2200(ActivityThread.java:上的handleStopService(ActivityThread.java:2941)148)at android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1395)at android.os.Handler.dispatchMessage(Handler.java:102)at android.os.Looper.loop(Looper.java:135) android.app.ActivityThread.main(ActivityThread.java:5310)在java.lang.reflect.Method.invoke(本机方法)在java.lang.reflect.Method.invoke(Method.java:372)at com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:901)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)造成原因:java.lang.IllegalArgumentException :未注册接收者:com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584在android.app.LoadedApk.forgetReceiverDispatcher(LoadedApk.java:769)在android.app.ContextImpl.unregisterReceiver(ContextImpl.java:1794)位于android.content.ContextWrapper.unregisterReceiver(ContextWrapper.java:510)位于com.google.android.exoplayer.demo.player.PlayService.onDestroy(PlayService.java:542)位于android.app.ActivityThread.handleStopService(ActivityThread) .java:2924),位于android.app.ActivityThread.access $ 2200(ActivityThread.java:148),位于android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1395)在android.os.Handler.dispatchMessage(Handler.java:102)在android.os.Looper.loop(Looper.java:135)在android.app.ActivityThread.main(ActivityThread.java:5310)在java。 com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java :)上java.lang.reflect.Method.invoke(Method.java:372)上的lang.reflect.Method.invoke(本机方法):901),位于com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696) 


这是对这个问题的真正答案!只是不要忘记您之前是否注册了全局或本地接收者
user924 '19

23

到处使用此代码进行unregisterReceiver:

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

6
仍然发生在我身上。最好使用try-catch。
palindrom

2
尝试捕获语句更好
Rowland Mtetezi

16

正如其他答案中提到的那样,由于未对的每次调用registerReceiver都恰好与对的一次调用相匹配,因此引发了异常unregisterReceiver。为什么不?

一个Activity并不总是有一个匹配onDestroy呼吁每个onCreate呼叫。如果系统内存不足,则会退出您的应用,而无需调用onDestroy

registerReceiver拨打电话的正确位置是在onResume通话中,unregisterReceiveronPause。这对电话总是匹配的。有关更多详细信息,请参见活动生命周期图。 http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle

您的代码将更改为:

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);
}

但这将导致注册和注销次数更多的开销。我不确定开销多少,但是肯定会有一些。
阿曼(Aman Deep Gautam)2015年

2
您是否真的建议留下一个抛出无效处理程序的异常,因为这将花费一些CPU周期才能将其删除?
Curmudgeonlybumbly

11

编辑:这是对inazaruk和电头的答案...我遇到了一个类似的问题,他们发现了以下内容...

此问题有一个长期存在的错误:http : //code.google.com/p/android/issues/detail?id=6191

看起来它始于Android 2.1,此后一直存在于所有Android 2.x版本中。我不确定在Android 3.x或4.x中是否仍然存在问题。

无论如何,此StackOverflow帖子说明了如何正确解决此问题(URL看起来不相关,但我保证是这样)

为什么键盘滑键使我的应用程序崩溃?


8

我使用了try-catch块来临时解决问题。

// 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

将接收者声明为null,然后分别在活动的onResume()和onPause()中放置注册和注销方法。

@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

注册BR的UI组件被销毁时,BR也被销毁。因此,当代码要注销时,BR可能已被破坏。


0

对于任何会遇到此问题并尝试了所有建议但仍然无法解决的问题的人,这就是我对问题进行排序的方式,而不是LocalBroadcastManager.getInstance(this).registerReceiver(...) 首先创建LocalBroadcastManager类型的局部变量,

private LocalBroadcastManager lbman;

并使用此变量在广播接收器上进行注册和注销,即

lbman.registerReceiver(bReceiver);

lbman.unregisterReceiver(bReceiver);

0

假设您broadcastReceiver的定义如下:

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

        // your code

    }
};

如果您LocalBroadcast在Activity 中使用,则可以通过以下方式注销:

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

如果您LocalBroadcast在Fragment 中使用,那么这将是您注销的方式:

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

如果您在“活动”中使用常规广播,则可以通过以下方式注销:

unregisterReceiver(broadcastReceiver);

如果您在Fragment中使用普通广播,那么这将是您注销的方式:

getActivity().unregisterReceiver(broadcastReceiver);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.