Empfänger nicht registriert Ausnahmefehler?

112

In meiner Entwicklerkonsole wird ständig ein Fehler gemeldet, den ich auf keinem Telefon reproduzieren kann. Eine Person hat eine Nachricht hinterlassen, dass sie diese erhält, wenn sie versucht, den Einstellungsbildschirm meines Batteriedienstes zu öffnen. Wie Sie dem Fehler entnehmen können, heißt es, dass der Empfänger nicht registriert ist.

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)

Ich registriere mich in meinem 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);
}

Heben Sie die Registrierung in onDestroy und auch bei einem bevorzugten Listener auf

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

}

und das ist mein empfänger im 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);
    }       
}

Irgendeine Idee, warum sie diesen Fehler bekommen würden?

tyczj
quelle

Antworten:

207

Die Wurzel Ihres Problems befindet sich hier:

 unregisterReceiver(batteryNotifyReceiver);

Wenn der Empfänger bereits nicht registriert war (wahrscheinlich in dem Code, den Sie nicht in diesen Beitrag aufgenommen haben) oder nicht registriert war, rufen Sie zu unregisterReceiverWürfen auf IllegalArgumentException. In Ihrem Fall müssen Sie für diese Ausnahme nur einen speziellen Versuch / Fang unregisterReceiverausführen und ihn ignorieren (vorausgesetzt, Sie können oder möchten nicht steuern, wie oft Sie auf demselben Empfänger anrufen).

inazaruk
quelle
31
Kann die Android-Plattform dies selbst tun? Ich hatte einen ähnlichen Code wie oben, aber keinen anderen Code, der die Registrierung des Dienstes aufheben würde, und ich erhalte dieselbe Ausnahme.
Electrichead
2
Ich habe das gleiche Problem @electrichead, ich kann nicht sehen, wo der Empfänger vor onDestroy () abgemeldet werden würde, es sei denn, Android tut es irgendwo für mich ....
user1088166
@ user1088166, versuchen Sie, die onStop () -Methode für Ihre Aktivität zu überschreiben. Fügen Sie dort einen Try-Catch hinzu (IllegalArgumentException e) und heben Sie die Registrierung Ihrer Sendung absichtlich auf - sehen Sie, ob dies
hilfreich
In meinem Fall war der Täter eine verzögerte Initialisierung. Ich habe die Registrierung übersprungen, weil das Objekt nicht initialisiert wurde. Daher wurde es später initialisiert und ich habe die Registrierung des Empfängers vergessen.
Boris Treukhov
@electrichead nein, es tut es nicht für Sie, Sie müssen nur die richtige Methode wählen: LocalBroadcastManager.getInstance(context).unregisterReceiver()odercontext.unregisterReceiver()
user924
25

Seien Sie vorsichtig, wenn Sie sich bei registrieren

LocalBroadcastManager.getInstance(this).registerReceiver()

Sie können sich nicht abmelden

 unregisterReceiver()

Sie müssen verwenden

LocalBroadcastManager.getInstance(this).unregisterReceiver()

oder App stürzt ab, protokollieren Sie wie folgt:

09-30 14: 00: 55.458 19064-19064 / com.jialan.guangdian.view E / AndroidRuntime: FATAL EXCEPTION: Hauptprozess: com.jialan.guangdian.view, PID: 19064 java.lang.RuntimeException: Dienst kann nicht beendet werden com.google.android.exoplayer.demo.player.PlayService@141ba331: java.lang.IllegalArgumentException: Empfänger nicht registriert: com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584 at android.app.ActivityT. handleStopService (ActivityThread.java:2941) unter android.app.ActivityThread.access $ 2200 (ActivityThread.java:148) bei android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1395) bei android.os.Handler.dispatchMessage (Handler.java:102) bei android.os.Looper.loop (Looper.java:135) bei android.app.ActivityThread.main (ActivityThread.java:5310) unter java.lang.reflect.Method.invoke (native Methode) unter java.lang.reflect.Method.invoke (Method.java:372) unter com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:901) unter com.android.internal.os.ZygoteInit.main (ZygoteInit.java:696) Auslöser: java.lang.IllegalArgumentException : Empfänger nicht registriert: com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584 at android.app.LoadedApk.forgetReceiverDispatcher (LoadedApk.java:769) at android.app.ContextImpl.unregisterRce:1794) unter android.content.ContextWrapper.unregisterReceiver (ContextWrapper.java:510) unter com.google.android.exoplayer.demo.player.PlayService.onDestroy (PlayService.java:542) unter android.app.ActivityThread.handleStopService (ActivityThread.handleStopService) .java: 2924) bei android.app.ActivityThread.access $ 2200 (ActivityThread.java:148) bei android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1395) bei android.os.Handler.dispatchMessage (Handler.java:102) bei android.os.Looper.loop (Looper.java:135) bei android.app.ActivityThread.main (ActivityThread.java:5310) bei Java. lang.reflect.Method.invoke (native Methode) unter java.lang.reflect.Method.invoke (Method.java:372) unter com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:901) unter com.android.internal.os.ZygoteInit.main (ZygoteInit.java:696) 

Chuanhang.gu
quelle
Dies ist eine echte Antwort auf dieses Problem! Vergessen Sie nur nicht, ob Sie zuvor einen globalen oder lokalen Empfänger registriert haben
user924
23

Verwenden Sie diesen Code überall für unregisterReceiver:

if (batteryNotifyReceiver != null) {
    unregisterReceiver(batteryNotifyReceiver);
    batteryNotifyReceiver = null;
}
xnagyg
quelle
6
Passiert mir immer noch. Verwenden Sie besser Try-Catch.
Palindrom
2
Versuchen Sie, Fang Aussage ist besser
Rowland Mtetezi
16

Wie in anderen Antworten erwähnt, wird die Ausnahme ausgelöst, da nicht jeder Anruf an registerReceivermit genau einem Anruf an übereinstimmt unregisterReceiver. Warum nicht?

An Activityhat nicht immer onDestroyfür jeden onCreateAnruf einen passenden Anruf. Wenn dem System der Speicher ausgeht, wird Ihre App ohne Aufruf entfernt onDestroy.

Der richtige Ort zum Tätigen eines registerReceiverAnrufs befindet sich im onResumeAnruf und unregisterReceiverin onPause. Dieses Anrufpaar ist immer übereinstimmend. Weitere Informationen finden Sie im Aktivitätslebenszyklusdiagramm. http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle

Ihr Code würde sich ändern zu:

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);
}
Curmudgeonlybumbly
quelle
Dies würde jedoch den Aufwand für das mehr- und mehrmalige Registrieren und Aufheben der Registrierung verursachen. Ich bin mir nicht sicher, wie hoch der Overhead ist, aber es wird sicher einige geben.
Aman Deep Gautam
2
Schlagen Sie wirklich vor, eine Ausnahme zu belassen, die einen ungültigen Handler auslöst, da das Entfernen einige CPU-Zyklen kosten würde?
Curmudgeonlybumbly
11

EDIT: Dies ist die Antwort für Inazaruk und Electrichead ... Ich war auf ein ähnliches Problem gestoßen und fand Folgendes heraus ...

Hier gibt es einen langjährigen Fehler für dieses Problem: http://code.google.com/p/android/issues/detail?id=6191

Es sieht so aus, als ob es um Android 2.1 herum gestartet wurde und seitdem in allen Android 2.x-Versionen vorhanden ist. Ich bin mir nicht sicher, ob es in Android 3.x oder 4.x immer noch ein Problem ist.

Wie auch immer, dieser StackOverflow-Beitrag erklärt, wie man das Problem richtig umgeht (es sieht nach der URL nicht relevant aus, aber ich verspreche es).

Warum stürzt die Tastatur-Folie in meiner App ab?

Justin
quelle
8

Ich habe einen Try-Catch-Block verwendet, um das Problem vorübergehend zu lösen.

// 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();
                }
            }
        }
Rowland Mtetezi
quelle
3

Deklarieren Sie den Empfänger als null und setzen Sie dann die Register- und Aufhebungsmethoden in onResume () bzw. onPause () der Aktivität.

@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;
    }
}
Sagar D.
quelle
0

Wenn die UI-Komponente, die den BR registriert, zerstört wird, wird auch der BR zerstört. Wenn der Code die Registrierung aufhebt, wurde der BR möglicherweise bereits zerstört.

ousanmaz
quelle
0

Für jeden, der auf dieses Problem LocalBroadcastManager.getInstance(this).registerReceiver(...) stößt und alles versucht hat, was vorgeschlagen wurde und nichts funktioniert, habe ich mein Problem auf diese Weise sortiert, anstatt zuerst eine lokale Variable vom Typ LocalBroadcastManager zu erstellen.

private LocalBroadcastManager lbman;

Und diese Variable verwendet, um das Registrieren und Aufheben der Registrierung auf dem Rundfunkempfänger durchzuführen, das heißt

lbman.registerReceiver(bReceiver);

und

lbman.unregisterReceiver(bReceiver);
Nada
quelle
0

Nehmen wir an, Ihr broadcastReceiverist wie folgt definiert:

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

        // your code

    }
};

Wenn Sie LocalBroadcastin einer Aktivität verwenden, können Sie die Registrierung auf folgende Weise aufheben:

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

Wenn Sie LocalBroadcastin einem Fragment verwenden, heben Sie die Registrierung auf folgende Weise auf:

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

Wenn Sie in einer Aktivität eine normale Sendung verwenden, können Sie die Registrierung auf folgende Weise aufheben:

unregisterReceiver(broadcastReceiver);

Wenn Sie eine normale Sendung in einem Fragment verwenden, können Sie die Registrierung auf folgende Weise aufheben:

getActivity().unregisterReceiver(broadcastReceiver);
Zeeshan
quelle