Dans ma console de développeur, les utilisateurs continuent de signaler une erreur que je ne peux pas reproduire sur aucun de mes téléphones. Une personne a laissé un message l'informant qu'elle l'obtient lorsqu'elle tente d'ouvrir l'écran des paramètres de mon service de batterie. Comme vous pouvez le constater, il est indiqué que le récepteur n’est pas enregistré.
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)
Je m'inscris est dans mon 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);
}
Se désinscrire dans onDestroy et aussi avec un écouteur de préférence
@Override
public void onDestroy(){
super.onDestroy();
unregisterReceiver(batteryNotifyReceiver);
}
et ceci est mon récepteur au 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);
}
}
aucune idée pourquoi ils obtiendraient cette erreur?
La racine de votre problème se trouve ici:
unregisterReceiver(batteryNotifyReceiver);
Si le destinataire était déjà désinscrit (probablement dans le code que vous n'avez pas inclus dans ce message) ou n'était pas enregistré, appelez alors unregisterReceiver
jette IllegalArgumentException
. Dans votre cas, vous avez juste besoin de mettre try/catch spécial pour cette exception et de l'ignorer (en supposant que vous ne pouvez ou ne voulez pas contrôler le nombre de fois que vous appelez unregisterReceiver
sur le même destinataire).
Attention, lorsque vous vous inscrivez par
LocalBroadcastManager.getInstance(this).registerReceiver()
vous ne pouvez pas vous désinscrire par
unregisterReceiver()
tu dois utiliser
LocalBroadcastManager.getInstance(this).unregisterReceiver()
ou l'application va planter, connectez-vous comme suit:
09-30 14: 00: 55.458 19064-19064/com.jialan.guangdian.view E/AndroidRuntime: EXCEPTION FATALE: processus principal: com.jialan.guangdian.view, PID: 19064 Java.lang.RuntimeException: Impossible d'arrêter le service com.google.Android.exoplayer.demo.player.PlayService@141ba331: Java.lang.IllegalArgumentException: Récepteur non enregistré: com.google.Android.exoplayer.demo.player.PlayService$PlayServus$PlayStatusReceiver@19538584 sur Android.application. handleStopService (ActivityThread.Java:2941) à 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.lang.reflect.Method.invoke (Méthode native) à Java.lang.reflect.Method.invoke (Method.Java:372) à com.Android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.Java:901) à com.Android.internal.os.ZygoteInit.main (ZygoteInit.Java:696) Causée par: Java.lang.IllegalArgumentException: Récepteur non enregistré: com.google.Android.exoplayer.demo.player.PlayStatusReceiver@19538584 à Android.app.LoadedApk 769) sur Android.app.ContextImpl.unregisterReceiver (ContextImpl.Java:1794) sur Android.content.ContextWrapper.unregisterReceiver (ContextWrapper.Java:510) sur com.google.Android.exoplayer.demo.player.PlayService.onDestroy (PlayServ .Java: 542) à Android.app.ActivityThread.handleStopService (ActivityThread.Java:2924) à Android.app.ActivityThread.access $ 2200 (ActivityThread.Java:148) à Android.app.ActivitéThread $ H.handleMessage (ActivityThread.Java : 1395) sur Android.os.Handler.dispatchMessage (Handler.Java:102) sur Android.os.Looper.loop (Looper.Java:135) sur Android.app.ActivityThread.main (ActivityThread.Java:5310) sur Java .lang.reflect.Method.invoke (Méthode native) sur Java.lang.reflect.Method.invoke (Method.Java:372) sur com.Android.internal.os.Zygo teInit $ MethodAndArgsCaller.run (ZygoteInit.Java:901) sur com.Android.internal.os.ZygoteInit.main (ZygoteInit.Java:696)
Utilisez ce code partout pour unregisterReceiver:
if (batteryNotifyReceiver!=null) {
unregisterReceiver(batteryNotifyReceiver);
batteryNotifyReceiver=null;
}
Comme mentionné dans d'autres réponses, l'exception est levée car chaque appel à registerReceiver
ne correspond pas à un seul appel à unregisterReceiver
. Pourquoi pas?
Un Activity
ne possède pas toujours un appel onDestroy
correspondant pour chaque appel onCreate
. Si le système manque de mémoire, votre application est expulsée sans appeler onDestroy
.
Le bon endroit pour mettre un appel registerReceiver
est dans l'appel onResume
et unregisterReceiver
dans onPause
. Cette paire d'appels est toujours appariée. Voir le diagramme de cycle de vie d'activité pour plus de détails. http://developer.Android.com/reference/Android/app/Activity.html#ActivityLifecycle
Votre code changerait à:
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);
}
Il existe un bogue de longue date concernant ce problème ici: http://code.google.com/p/Android/issues/detail?id=6191
On dirait que cela a commencé autour de Android 2.1 et est présent dans toutes les Android 2.x versions depuis. Je ne suis pas sûr qu'il s'agisse toujours d'une problème dans Android 3.x ou 4.x cependant.
Quoi qu'il en soit, cet article de StackOverflow explique comment résoudre correctement le problème (il n'a pas l'air pertinent par l'URL, mais je vous promets que c'est le cas)
J'ai utilisé un bloc try - catch pour résoudre le problème temporairement.
// 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();
}
}
}
Déclarez le destinataire comme nul, puis placez les méthodes register et unsregister dans onResume () et onPause () de l'activité, respectivement.
@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;
}
}
Pour tous ceux qui rencontreront ce problème et essaieront tout ce qui a été suggéré et que rien ne fonctionne toujours, c’est ainsi que j’ai réglé mon problème, au lieu de faire LocalBroadcastManager.getInstance(this).registerReceiver(...)
j’ai d’abord créé une variable locale de type LocalBroadcastManager,
private LocalBroadcastManager lbman;
Et utilisé cette variable pour effectuer l’enregistrement et l’annulation de l’enregistrement sur le destinataire, c’est-à-dire
lbman.registerReceiver(bReceiver);
et
lbman.unregisterReceiver(bReceiver);
Lorsque le composant d'interface utilisateur qui enregistre le BR est détruit, le BR l'est également. Par conséquent, lorsque le code se désinscrit, le BR peut déjà avoir été détruit.