Receptor não registrado erro de exceção?

112

Em meu console de desenvolvedor, as pessoas continuam relatando um erro que não consigo reproduzir em nenhum telefone que possuo. Uma pessoa deixou uma mensagem dizendo que entende quando tenta abrir a tela de configurações do meu serviço de bateria. Como você pode ver no erro diz que o receptor não 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)

Eu me registro no meu 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);
}

Cancelar o registro em onDestroy e também com um ouvinte de preferência

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

}

e este é meu receptor no serviço

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

alguma ideia de por que eles estariam recebendo esse erro?

tyczj
fonte

Respostas:

207

A raiz do seu problema está localizada aqui:

 unregisterReceiver(batteryNotifyReceiver);

Se o receptor já não estava registrado (provavelmente no código que você não incluiu nesta postagem) ou não estava registrado, chame para unregisterReceiverthrows IllegalArgumentException. No seu caso, você precisa apenas colocar try / catch especial para esta exceção e ignorá-la (assumindo que você não pode ou não deseja controlar o número de vezes que você chama unregisterReceiverno mesmo receptor).

inazaruk
fonte
31
É possível que a própria plataforma Android faça isso? Eu tinha um código semelhante ao acima, mas sem nenhum outro código que cancelasse o registro do serviço e recebo a mesma exceção.
electrichead
2
Tenho o mesmo problema @electrichead, não consigo ver onde o receptor seria desregistrado antes de onDestroy (), a menos que o Android esteja fazendo isso por mim em algum lugar ...
user1088166
@ user1088166, tente substituir o método onStop () para sua atividade. Lá, adicione um try catch (IllegalArgumentException e) e cancele o registro de sua transmissão de propósito - veja se isso ajuda (notei que este é um comentário de 3 anos :))
Nactus
No meu caso, o culpado foi a inicialização lenta - pulei o registro porque o objeto não foi inicializado, então foi inicializado mais tarde e esqueci o registro do receptor.
Boris Treukhov
@electrichead não, não serve para você, você só precisa escolher o método correto: LocalBroadcastManager.getInstance(context).unregisterReceiver()oucontext.unregisterReceiver()
user924
25

Tenha cuidado ao se registrar por

LocalBroadcastManager.getInstance(this).registerReceiver()

você não pode cancelar o registro por

 unregisterReceiver()

você deve usar

LocalBroadcastManager.getInstance(this).unregisterReceiver()

ou o aplicativo travará, faça o seguinte:

30/09 14: 00: 55.458 19064-19064 / com.jialan.guangdian.view E / AndroidRuntime: EXCEÇÃO FATAL: Processo principal: com.jialan.guangdian.view, PID: 19064 java.lang.RuntimeException: Não foi possível interromper o serviço com.google.android.exoplayer.demo.player.PlayService@141ba331: java.lang.IllegalArgumentException: Receptor não registrado: com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584 em android.app.ActivityThread. handleStopService (ActivityThread.java:2941) em android.app.ActivityThread.access $ 2200 (ActivityThread.java:148) em android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1395) em android.os.Handler.dispatchMessage (Handler.java:102) em android.os.Looper.loop (Looper.java:135) em android.app.ActivityThread.main (ActivityThread.java:5310) em java.lang.reflect.Method.invoke (Native Method) em java.lang.reflect.Method.invoke (Method.java:372) em com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:901) em com.android.internal.os.ZygoteInit.main (ZygoteInit.java:696) Causado por: java.lang.IllegalArgumentException : Receptor não registrado: com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584 em android.app.LoadedApk.forgetReceiverDispatcher (LoadedApk.java:769) em android.app.ContextImpl.unregisterReceiver (ContextImpl.unregisterReceiver1794) em android.content.ContextWrapper.unregisterReceiver (ContextWrapper.java:510) em com.google.android.exoplayer.demo.player.PlayService.onDestroy (PlayService.java:542) em android.app.ActivityThread.handleStopService (ActivityThread .java: 2924) em android.app.ActivityThread.access $ 2200 (ActivityThread.java:148) em android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1395) em android.os.Handler.dispatchMessage (Handler.java:102) em android.os.Looper.loop (Looper.java:135) em android.app.ActivityThread.main (ActivityThread.java:5310) em java. lang.reflect.Method.invoke (Native Method) em java.lang.reflect.Method.invoke (Method.java:372) em com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:901) em com.android.internal.os.ZygoteInit.main (ZygoteInit.java:696) 

Chuanhang.gu
fonte
Esta é uma resposta real para este problema! Apenas não se esqueça se você registrou um receptor global ou local antes
usuário924
23

Use este código em qualquer lugar para unregisterReceiver:

if (batteryNotifyReceiver != null) {
    unregisterReceiver(batteryNotifyReceiver);
    batteryNotifyReceiver = null;
}
xnagyg
fonte
6
Ainda acontece comigo. Melhor usar try-catch.
Palindrom
2
Tente a declaração de captura é melhor
Rowland Mtetezi
16

Conforme mencionado em outras respostas, a exceção está sendo lançada porque cada chamada para registerReceivernão está sendo correspondida por exatamente uma chamada para unregisterReceiver. Por que não?

Um Activitynão tem sempre uma correspondência onDestroychamada para cada onCreatechamada. Se o sistema ficar sem memória, seu aplicativo será despejado sem chamada onDestroy.

O local correto para fazer uma registerReceiverchamada é na onResumechamada e unregisterReceiverem onPause. Este par de chamadas é sempre correspondido. Consulte o diagrama do ciclo de vida da atividade para obter mais detalhes. http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle

Seu código mudaria para:

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);
}
Mesquinho
fonte
Mas isso causaria a sobrecarga de registrar e cancelar o registro muito mais vezes. Não tenho certeza da quantidade de overhead, mas haverá alguns com certeza.
Aman Deep Gautam,
2
Você está realmente sugerindo deixar uma exceção lançando um manipulador inválido porque custaria alguns ciclos de CPU para removê-lo?
Curmudgeonlybumbly
11

EDIT: Esta é a resposta para inazaruk e electrichead ... Eu tive um problema semelhante para eles e descobri o seguinte ...

Há um bug antigo para esse problema aqui: http://code.google.com/p/android/issues/detail?id=6191

Parece que tudo começou em torno do Android 2.1 e está presente em todas as versões do Android 2.x desde então. Não tenho certeza se ainda é um problema no Android 3.x ou 4.x.

De qualquer forma, esta postagem StackOverflow explica como contornar o problema corretamente (não parece relevante pelo URL, mas eu prometo que é)

Por que o slide do teclado trava meu aplicativo?

Justin
fonte
8

Usei um bloco try-catch para resolver o problema temporariamente.

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

Declare o receptor como nulo e, a seguir, coloque os métodos de registro e cancelamento de registro em onResume () e onPause () da atividade, 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
fonte
0

Quando o componente de IU que registra o BR é destruído, o BR também é. Portanto, quando o código chega ao cancelamento do registro, o BR pode já ter sido destruído.

ousanmaz
fonte
0

Para qualquer pessoa que se deparar com esse problema e tentar tudo o que foi sugerido e nada ainda funciona, foi assim que resolvi meu problema, em vez de fazer LocalBroadcastManager.getInstance(this).registerReceiver(...) primeiro criei uma variável local do tipo LocalBroadcastManager,

private LocalBroadcastManager lbman;

E utilizou esta variável para realizar o cadastramento e o cancelamento do cadastramento no emissor, ou seja,

lbman.registerReceiver(bReceiver);

e

lbman.unregisterReceiver(bReceiver);
nada
fonte
0

Vamos supor que seu broadcastReceiverseja definido assim:

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

        // your code

    }
};

Se você estiver usando LocalBroadcastem uma atividade, é assim que cancelará o registro:

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

Se você estiver usando LocalBroadcastem um fragmento, é assim que cancelará o registro:

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

Se você estiver usando uma transmissão normal em uma atividade, é assim que cancelará o registro:

unregisterReceiver(broadcastReceiver);

Se você estiver usando transmissão normal em um Fragment, é assim que você cancelará o registro:

getActivity().unregisterReceiver(broadcastReceiver);
Zeeshan
fonte