A simple solution to this problem is to call the registerReceiver() in your Custom Application Class. This will ensure that your Broadcast receiver will be called only one in your entire Application lifecycle.
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);
}
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?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With