¿Receptor no registrado error de excepción?

112

En mi consola de desarrollador, la gente sigue informando un error que no puedo reproducir en ningún teléfono que tenga. Una persona dejó un mensaje diciendo que lo entendió cuando intentaron abrir la pantalla de configuración de mi servicio de batería. Como puede ver en el error, dice que el receptor no está registrado.

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)

Me registro está en mi 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);
}

Anular el registro en onDestroy y también con un oyente de preferencia

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

}

y este es mi receptor en el servicio

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

¿Alguna idea de por qué obtendrían ese error?

tyczj
fuente

Respuestas:

207

La raíz de su problema se encuentra aquí:

 unregisterReceiver(batteryNotifyReceiver);

Si el receptor ya no estaba registrado (probablemente en el código que no incluyó en esta publicación) o no estaba registrado, llame a unregisterReceiverthrows IllegalArgumentException. En su caso, debe poner un try / catch especial para esta excepción e ignorarla (asumiendo que no puede o no quiere controlar la cantidad de veces que llama unregisterReceiveral mismo receptor).

inazaruk
fuente
31
¿Es posible que la propia plataforma Android haga esto? Tenía un código similar al anterior, pero sin ningún otro código que anularía el registro del servicio, y obtengo la misma excepción.
electrichead
2
Tengo el mismo problema @electrichead, no puedo ver dónde se anularía el registro del receptor antes de onDestroy () a menos que Android lo esté haciendo por mí en algún lugar ...
user1088166
@ user1088166, intente anular el método onStop () para su actividad. Allí, agregue un try catch (IllegalArgumentException e) y anule el registro intencionalmente de su transmisión; vea si eso ayuda (acabo de notar que este es un comentario de 3 años :))
Nactus
En mi caso, el culpable fue la inicialización perezosa: omití el registro porque el objeto no se inicializó, por lo que se inicializó más tarde y olvidé el registro del receptor.
Boris Treukhov
@electrichead no, no lo hace por usted, solo necesita elegir el método correcto: LocalBroadcastManager.getInstance(context).unregisterReceiver()ocontext.unregisterReceiver()
user924
25

Tenga cuidado, cuando se registre por

LocalBroadcastManager.getInstance(this).registerReceiver()

no puedes cancelar el registro por

 unregisterReceiver()

debes usar

LocalBroadcastManager.getInstance(this).unregisterReceiver()

o la aplicación se bloqueará, inicie sesión de la siguiente manera:

09-30 14: 00: 55.458 19064-19064 / com.jialan.guangdian.view E / AndroidRuntime: FATAL EXCEPTION: main Proceso: com.jialan.guangdian.view, PID: 19064 java.lang.RuntimeException: No se puede detener el servicio com.google.android.exoplayer.demo.player.PlayService@141ba331: java.lang.IllegalArgumentException: Receptor no registrado: com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584 en android.app.ActivityThread. handleStopService (ActivityThread.java:2941) en android.app.ActivityThread.access $ 2200 (ActivityThread.java:148) en android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1395) en android.os.Handler.dispatchMessage (Handler.java:102) en android.os.Looper.loop (Looper.java:135) en android.app.ActivityThread.main (ActivityThread.java:5310) en java.lang.reflect.Method.invoke (método nativo) en java.lang.reflect.Method.invoke (Method.java:372) en com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:901) en com.android.internal.os.ZygoteInit.main (ZygoteInit.java:696) Causado por: java.lang.IllegalArgumentException : Receptor no registrado: com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584 en android.app.LoadedApk.forgetReceiverDispatcher (LoadedApk.java:769) en android.app.ContextImpl.unregisterReceiver (ContextImpl.java:1794) en android.content.ContextWrapper.unregisterReceiver (ContextWrapper.java:510) en com.google.android.exoplayer.demo.player.PlayService.onDestroy (PlayService.java:542) en android.app.ActivityThread.handleStopService (ActivityThread .java: 2924) en android.app.ActivityThread.access $ 2200 (ActivityThread.java:148) en android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1395) en android.os.Handler.dispatchMessage (Handler.java:102) en android.os.Looper.loop (Looper.java:135) en android.app.ActivityThread.main (ActivityThread.java:5310) en java. lang.reflect.Method.invoke (método nativo) en java.lang.reflect.Method.invoke (Method.java:372) en com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:901) en com.android.internal.os.ZygoteInit.main (ZygoteInit.java:696) 

Chuanhang.gu
fuente
¡Esta es una verdadera respuesta a este problema! No olvide si registró un receptor global o local antes
user924
23

Utilice este código en todas partes para unregisterReceiver:

if (batteryNotifyReceiver != null) {
    unregisterReceiver(batteryNotifyReceiver);
    batteryNotifyReceiver = null;
}
xnagyg
fuente
6
Todavía me pasa. Mejor use try-catch.
palindrom
2
Probar declaración de captura es mejor
Rowland Mtetezi
16

Como se mencionó en otras respuestas, la excepción se lanza porque cada llamada a registerReceiverno coincide exactamente con una llamada a unregisterReceiver. Por qué no?

An Activityno siempre tiene una onDestroyllamada coincidente para cada onCreatellamada. Si el sistema se queda sin memoria, su aplicación se desaloja sin llamar onDestroy.

El lugar correcto para poner una registerReceiverllamada en la onResumellamada, y unregisterReceiveren onPause. Este par de llamadas siempre coincide. Consulte el diagrama del ciclo de vida de la actividad para obtener más detalles. http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle

Tu código cambiaría a:

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);
}
Cascarrabias
fuente
Pero esto causaría la sobrecarga de registrarse y anular el registro muchas más veces. No estoy seguro de la cantidad de gastos generales, pero seguro que habrá algunos.
Aman Deep Gautam
2
¿Realmente está sugiriendo dejar una excepción que arroje un controlador no válido en su lugar porque costaría algunos ciclos de CPU eliminarlo?
Curmudgeonlybumbly
11

EDITAR: Esta es la respuesta para inazaruk y electrichead ... Me encontré con un problema similar y descubrí lo siguiente ...

Hay un error de larga data para este problema aquí: http://code.google.com/p/android/issues/detail?id=6191

Parece que comenzó alrededor de Android 2.1 y ha estado presente en todas las versiones de Android 2.x desde entonces. Sin embargo, no estoy seguro de si sigue siendo un problema en Android 3.xo 4.x.

De todos modos, esta publicación de StackOverflow explica cómo solucionar el problema correctamente (no parece relevante por la URL, pero prometo que lo es)

¿Por qué el deslizamiento del teclado bloquea mi aplicación?

Justin
fuente
8

Usé un bloque try - catch para resolver el problema temporalmente.

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

Declare el receptor como nulo y luego coloque los métodos register y unregister en onResume () y onPause () de la actividad respectivamente.

@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
fuente
0

Cuando se destruye el componente de la interfaz de usuario que registra el BR, también se destruye el BR. Por lo tanto, cuando el código se cancela, es posible que el BR ya haya sido destruido.

ousanmaz
fuente
0

Para cualquiera que se encuentre con este problema y haya intentado todo lo que se sugirió y nada todavía funciona, así es como solucioné mi problema, en lugar de hacerlo LocalBroadcastManager.getInstance(this).registerReceiver(...) , primero creé una variable local de tipo LocalBroadcastManager,

private LocalBroadcastManager lbman;

Y usé esta variable para llevar a cabo el registro y la cancelación del registro en el receptor de transmisión, es decir

lbman.registerReceiver(bReceiver);

y

lbman.unregisterReceiver(bReceiver);
nada
fuente
0

Supongamos que tu broadcastReceiverse define así:

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

        // your code

    }
};

Si está utilizando LocalBroadcasten una actividad, así es como anulará el registro:

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

Si está usando LocalBroadcasten un Fragmento, entonces así es como anulará el registro:

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

Si está utilizando la transmisión normal en una actividad, así es como anulará el registro:

unregisterReceiver(broadcastReceiver);

Si está utilizando la transmisión normal en un fragmento, así es como anulará el registro:

getActivity().unregisterReceiver(broadcastReceiver);
Zeeshan
fuente