Errore di eccezione del destinatario non registrato?


112

Nella mia console per sviluppatori le persone continuano a segnalare un errore che non posso riprodurre su nessun telefono in mio possesso. Una persona ha lasciato un messaggio dicendo che lo riceve quando tenta di aprire la schermata delle impostazioni del mio servizio batteria. Come puoi vedere dall'errore dice che il ricevitore non è registrato.

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)

Mi registro è nel mio 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);
}

Annulla la registrazione in onDestroy e anche con un ascoltatore di preferenze

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

}

e questo è il mio ricevitore nel servizio

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

qualche idea del motivo per cui avrebbero ricevuto quell'errore?

Risposte:


207

La radice del tuo problema si trova qui:

 unregisterReceiver(batteryNotifyReceiver);

Se il destinatario era già non registrato (probabilmente nel codice che non hai incluso in questo post) o non era registrato, chiama a unregisterReceiverthrows IllegalArgumentException. Nel tuo caso devi solo mettere un try / catch speciale per questa eccezione e ignorarla (supponendo che non puoi o non vuoi controllare il numero di volte in cui chiami unregisterReceiverlo stesso destinatario).


31
È possibile che la piattaforma Android stessa lo faccia? Avevo un codice simile al precedente, ma senza nessun altro codice che avrebbe annullato la registrazione del servizio e ottengo la stessa eccezione.
elettricista

2
Ho lo stesso problema @electrichead, non riesco a vedere dove il ricevitore sarebbe stato annullato prima di onDestroy () a meno che Android non lo facesse per me da qualche parte ....
user1088166

@ user1088166, prova a sovrascrivere il metodo onStop () per la tua attività. Lì aggiungi un tentativo di cattura (IllegalArgumentException e) e annulla di proposito la tua trasmissione - vedi se questo aiuta (ho appena notato che questo è un commento di 3 anni :))
Nactus

Nel mio caso il colpevole era l'inizializzazione pigra: ho saltato la registrazione perché l'oggetto non era inizializzato, quindi è stato inizializzato in seguito e ho dimenticato la registrazione del ricevitore.
Boris Treukhov

@electrichead no, non lo fa per te, devi solo scegliere il metodo corretto: LocalBroadcastManager.getInstance(context).unregisterReceiver() ocontext.unregisterReceiver()
user924

25

Fai attenzione quando ti registri tramite

LocalBroadcastManager.getInstance(this).registerReceiver()

non puoi annullare la registrazione tramite

 unregisterReceiver()

devi usare

LocalBroadcastManager.getInstance(this).unregisterReceiver()

o l'app andrà in crash, accedi come segue:

09-30 14: 00: 55.458 19064-19064 / com.jialan.guangdian.view E / AndroidRuntime: ECCEZIONE FATALE: Processo principale: com.jialan.guangdian.view, PID: 19064 java.lang.RuntimeException: Impossibile arrestare il servizio com.google.android.exoplayer.demo.player.PlayService@141ba331: java.lang.IllegalArgumentException: ricevitore non registrato: com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584 su android.app.ActivityThread. handleStopService (ActivityThread.java:2941) su android.app.ActivityThread.access $ 2200 (ActivityThread.java:148) su android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1395) su android.os.Handler.dispatchMessage (Handler.java:102) su android.os.Looper.loop (Looper.java:135) su android.app.ActivityThread.main (ActivityThread.java:5310) su java.lang.reflect.Method.invoke (Native Method) su java.lang.reflect.Method.invoke (Method.java:372) su com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:901) su com.android.internal.os.ZygoteInit.main (ZygoteInit.java:696) Causato da: java.lang.IllegalArgumentEx : Ricevitore non registrato: com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584 su android.app.LoadedApk.forgetReceiverDispatcher (LoadedApk.java:769) su android.app.ContextImpl.unregisterReceiver (ContextImjava:1794) su android.content.ContextWrapper.unregisterReceiver (ContextWrapper.java:510) su com.google.android.exoplayer.demo.player.PlayService.onDestroy (PlayService.java:542) su android.app.ActivityThread.handleStopService (ActivityThread .java: 2924) su android.app.ActivityThread.access $ 2200 (ActivityThread.java:148) su android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1395) su android.os.Handler.dispatchMessage (Handler.java:102) su android.os.Looper.loop (Looper.java:135) su android.app.ActivityThread.main (ActivityThread.java:5310) su java. lang.reflect.Method.invoke (Native Method) su java.lang.reflect.Method.invoke (Method.java:372) su com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:901) su com.android.internal.os.ZygoteInit.main (ZygoteInit.java:696) 


Questa è una vera risposta a questo problema! Non dimenticare se hai già registrato un ricevitore globale o locale
user924

23

Usa questo codice ovunque per unregisterReceiver:

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

6
Succede ancora a me. Meglio usare try-catch.
palindrom

2
Prova la dichiarazione di cattura è meglio
Rowland Mtetezi

16

Come accennato in altre risposte, l'eccezione viene generata perché ogni chiamata a registerReceivernon viene trovata esattamente da una chiamata a unregisterReceiver. Perchè no?

An Activitynon ha sempre una onDestroychiamata corrispondente per ogni onCreatechiamata. Se il sistema esaurisce la memoria, la tua app viene rimossa senza chiamare onDestroy.

Il posto corretto per effettuare una registerReceiverchiamata è nella onResumechiamata e unregisterReceiverin onPause. Questa coppia di chiamate è sempre abbinata. Vedere il diagramma del ciclo di vita dell'attività per ulteriori dettagli. http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle

Il tuo codice cambierebbe in:

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

Ma questo causerebbe il sovraccarico di registrazione e annullamento della registrazione molte più volte. Non sono sicuro della quantità di overhead, ma ce ne saranno di sicuro.
Aman Deep Gautam

2
Stai davvero suggerendo di lasciare un'eccezione che genera un gestore non valido perché costerebbe alcuni cicli della CPU per rimuoverlo?
Burmudgeonlybumbly

11

EDIT: Questa è la risposta per inazaruk ed electrichead ... mi sono imbattuto in un problema simile a loro e ho scoperto quanto segue ...

C'è un bug di vecchia data per questo problema qui: http://code.google.com/p/android/issues/detail?id=6191

Sembra che sia iniziato intorno ad Android 2.1 e da allora è stato presente in tutte le versioni di Android 2.x. Tuttavia, non sono sicuro che sia ancora un problema in Android 3.xo 4.x.

Ad ogni modo, questo post di StackOverflow spiega come risolvere correttamente il problema (non sembra pertinente per l'URL ma prometto che lo è)

Perché lo scorrimento della tastiera si blocca con la mia app?


8

Ho usato un blocco try - catch per risolvere temporaneamente il problema.

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

Dichiarare il ricevitore come null e quindi inserire i metodi di registro e annullamento della registrazione rispettivamente in onResume () e onPause () dell'attività.

@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

Quando il componente UI che registra il BR viene distrutto, lo è anche il BR. Pertanto, quando il codice viene annullato, il BR potrebbe essere già stato distrutto.


0

Per chiunque si imbattesse in questo problema e abbia provato tutto ciò che è stato suggerito e niente funziona ancora, è così che ho risolto il mio problema, invece di fare LocalBroadcastManager.getInstance(this).registerReceiver(...) ho prima creato una variabile locale di tipo LocalBroadcastManager,

private LocalBroadcastManager lbman;

E ha utilizzato questa variabile per effettuare la registrazione e l'annullamento della registrazione sul trasmettitore, ovvero

lbman.registerReceiver(bReceiver);

e

lbman.unregisterReceiver(bReceiver);

0

Supponiamo che il tuo broadcastReceiversia definito in questo modo:

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

        // your code

    }
};

Se stai utilizzando LocalBroadcastin un'attività, ecco come annullerai la registrazione:

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

Se stai usando LocalBroadcastin un frammento, ecco come annullerai la registrazione:

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

Se stai utilizzando la trasmissione normale in un'attività, ecco come annullare la registrazione:

unregisterReceiver(broadcastReceiver);

Se stai usando la trasmissione normale in un frammento, ecco come annullerai la registrazione:

getActivity().unregisterReceiver(broadcastReceiver);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.