开发者

Receiver not registered exception error?

In my developer console people keep reporting an error that I cannot reproduce on any phone I have. One person left a message saying he gets it when they try to open the settings screen of my battery service. As you can see from the error it says that the receiver is not registered.

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)

I register is in my onCreate

@Override
public void onCreate(){
    super.onCreate();
    SharedPreferences pref = PreferenceManag开发者_开发知识库er.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);
}

Unregister in onDestroy and also with a preference listener

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

}

and this is my receiver in the service

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

any idea why they would be getting that error?


The root of your problem is located here:

 unregisterReceiver(batteryNotifyReceiver);

If the receiver was already unregistered (probably in the code that you didn't include in this post) or was not registered, then call to unregisterReceiver throws IllegalArgumentException. In your case you need to just put special try/catch for this exception and ignore it (assuming you can't or don't want to control number of times you call unregisterReceiver on the same recevier).


Be careful, when you register by

LocalBroadcastManager.getInstance(this).registerReceiver()

you can't unregister by

 unregisterReceiver()

you must use

LocalBroadcastManager.getInstance(this).unregisterReceiver()

or app will crash, log as follow:

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: Unable to stop service com.google.android.exoplayer.demo.player.PlayService@141ba331: java.lang.IllegalArgumentException: Receiver not registered: com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584 at android.app.ActivityThread.handleStopService(ActivityThread.java:2941) at android.app.ActivityThread.access$2200(ActivityThread.java: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) at android.app.ActivityThread.main(ActivityThread.java:5310) at java.lang.reflect.Method.invoke(Native Method) at 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) Caused by: java.lang.IllegalArgumentException: Receiver not registered: com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584 at android.app.LoadedApk.forgetReceiverDispatcher(LoadedApk.java:769) at android.app.ContextImpl.unregisterReceiver(ContextImpl.java:1794) at android.content.ContextWrapper.unregisterReceiver(ContextWrapper.java:510) at com.google.android.exoplayer.demo.player.PlayService.onDestroy(PlayService.java:542) at android.app.ActivityThread.handleStopService(ActivityThread.java:2924) at android.app.ActivityThread.access$2200(ActivityThread.java: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)  at android.app.ActivityThread.main(ActivityThread.java:5310)  at java.lang.reflect.Method.invoke(Native Method)  at 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) 


Use this code everywhere for unregisterReceiver:

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


As mentioned in other answers, the exception is being thrown because each call to registerReceiver is not being matched by exactly one call to unregisterReceiver. Why not?

An Activity does not always have a matching onDestroy call for every onCreate call. If the system runs out of memory, your app is evicted without calling onDestroy.

The correct place to put a registerReceiver call is in the onResume call, and unregisterReceiver in onPause. This pair of calls is always matched. See the Activity lifecycle diagram for more details. http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle

Your code would change to:

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


EDIT: This is the answer for inazaruk and electrichead... I had run into a similar issue to them and found out the following...

There is a long-standing bug for this problem here: http://code.google.com/p/android/issues/detail?id=6191

Looks like it started around Android 2.1 and has been present in all of the Android 2.x releases since. I'm not sure if it is still a problem in Android 3.x or 4.x though.

Anyway, this StackOverflow post explains how to workaround the problem correctly (it doesn't look relevant by the URL but I promise it is)

Why does keyboard-slide crash my app?


I used a try - catch block to solve the issue temporarily.

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


Declare receiver as null and then Put register and unregister methods in onResume() and onPause() of the activity respectively.

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


When the UI component that registers the BR is destroyed, so is the BR. Therefore when the code gets to unregistering, the BR may have already been destroyed.


For anybody who will come upon this problem and they tried all that was suggested and nothing still works, this is how I sorted my problem, instead of doing LocalBroadcastManager.getInstance(this).registerReceiver(...) I first created a local variable of type LocalBroadcastManager,

private LocalBroadcastManager lbman;

And used this variable to carry out the registering and unregistering on the broadcastreceiver, that is

lbman.registerReceiver(bReceiver);

and

lbman.unregisterReceiver(bReceiver);


Lets assume your broadcastReceiver is defined like this:

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

        // your code

    }
};

If you are using LocalBroadcast in an Activity, then this is how you'll unregister:

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

If you are using LocalBroadcast in a Fragment, then this is how you'll unregister:

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

If you are using normal broadcast in an Activity, then this is how you'll unregister:

unregisterReceiver(broadcastReceiver);

If you are using normal broadcast in a Fragment, then this is how you'll unregister:

getActivity().unregisterReceiver(broadcastReceiver);


Unregister broadcast receiver in Try Catch

    try {
        unregisterReceiver(receiver);
    } catch (IllegalArgumentException e) {
        System.out.printf(e.getMessage());
    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜