Получатель не зарегистрировал ошибку исключения?

112

В моей консоли разработчика люди продолжают сообщать об ошибке, которую я не могу воспроизвести на любом своем телефоне. Один человек оставил сообщение о том, что он получает его, когда пытается открыть экран настроек моей службы аккумуляторов. Как видно из ошибки, там написано, что получатель не зарегистрирован.

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)

Я регистрируюсь в моем 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);
}

Отмените регистрацию в onDestroy, а также с предпочтительным слушателем

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

}

а это мой ресивер в сервисе

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

есть идеи, почему они получают эту ошибку?

tyczj
источник

Ответы:

207

Корень вашей проблемы находится здесь:

 unregisterReceiver(batteryNotifyReceiver);

Если получатель уже был незарегистрирован (возможно, в коде, который вы не включили в этот пост) или не был зарегистрирован, то вызов unregisterReceiverthrows IllegalArgumentException. В вашем случае вам нужно просто поставить специальный try / catch для этого исключения и игнорировать его (при условии, что вы не можете или не хотите контролировать количество вызовов unregisterReceiverодного и того же получателя).

Иназарук
источник
31
Может ли это сделать сама платформа Android? У меня был код, аналогичный приведенному выше, но без другого кода, который бы отменял регистрацию службы, и я получаю то же исключение.
electrichead
2
У меня та же проблема, @electrichead, я не вижу, где приемник будет разрегистрирован до onDestroy (), если Android не сделает это за меня где-то ....
user1088166 05
@ user1088166, попробуйте переопределить метод onStop () для своего действия. Там добавьте try catch (IllegalArgumentException e) и намеренно отмените регистрацию вашей трансляции - посмотрите, поможет ли это (только что заметил, что это комментарий трехлетней давности :))
Nactus
В моем случае виновником была ленивая инициализация - я пропустил регистрацию, потому что объект не был инициализирован, поэтому он был инициализирован позже, и я забыл о регистрации получателя.
Борис Треухов
@electrichead нет, он не делает этого за вас, вам просто нужно выбрать правильный метод: LocalBroadcastManager.getInstance(context).unregisterReceiver()илиcontext.unregisterReceiver()
user924
25

Будьте осторожны, когда вы регистрируетесь

LocalBroadcastManager.getInstance(this).registerReceiver()

вы не можете отменить регистрацию

 unregisterReceiver()

вы должны использовать

LocalBroadcastManager.getInstance(this).unregisterReceiver()

или приложение выйдет из строя, зарегистрируйтесь следующим образом:

09-30 14: 00: 55.458 19064-19064 / com.jialan.guangdian.view E / Android Время выполнения: ФАТАЛЬНОЕ ИСКЛЮЧЕНИЕ: основной процесс: com.jialan.guangdian.view, PID: 19064 java.lang.RuntimeException: невозможно остановить службу com.google.android.exoplayer.demo.player.PlayService@141ba331: java.lang.IllegalArgumentException: Получатель не зарегистрирован: com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584 в android.app.ActivityThread. 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 (собственный метод) в 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) Вызвано: java.lang.IllegalArgument : Получатель не зарегистрирован: com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584 в android.app.LoadedApk.forgetReceiverDispatcher (LoadedApk.java:769) в android.app.ContextImpl.unImplisterReceiver (1794) в android.content.ContextWrapper.unregisterReceiver (ContextWrapper.java:510) в com.google.android.exoplayer.demo.player.PlayService.onDestroy (PlayService.java:542) в android.app.ActivityThread.handleStopService (ActivityThread .java: 2924) в 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 (собственный метод) в 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) 

Chuanhang.gu
источник
Это настоящий ответ на эту проблему! Только не забывайте, регистрировали ли вы глобальный или локальный приемник раньше
user924,
23

Используйте этот код везде для unregisterReceiver:

if (batteryNotifyReceiver != null) {
    unregisterReceiver(batteryNotifyReceiver);
    batteryNotifyReceiver = null;
}
xnagyg
источник
6
Со мной все еще случается. Лучше использовать try-catch.
палиндром
2
Лучше попробуйте выражение catch
Rowland Mtetezi
16

Как упоминалось в других ответах, создается исключение, потому что каждый вызов registerReceiverне соответствует ровно одному вызову unregisterReceiver. Почему нет?

ActivityНе всегда имеет соответствующий onDestroyвызов для каждого onCreateвызова. Если системе не хватает памяти, ваше приложение удаляется без вызова onDestroy.

Правильное место для registerReceiverзвонка - это onResumeзвонок и unregisterReceiverвход onPause. Эта пара вызовов всегда совпадает. См. Схему жизненного цикла Activity для получения более подробной информации. http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle

Ваш код изменится на:

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);
}
Скряга только тупо
источник
Но это вызовет накладные расходы на регистрацию и отмену регистрации еще много раз. Я не уверен в размере накладных расходов, но наверняка они будут.
Аман Дип Гаутам
2
Вы действительно предлагаете оставить на месте исключение, генерирующее недопустимый обработчик, потому что его удаление потребует некоторых циклов процессора?
Curmudgeonlybumbly
11

РЕДАКТИРОВАТЬ: Это ответ на иназарук и электрическую головку ... Я столкнулся с аналогичной проблемой и обнаружил следующее ...

Здесь есть давняя ошибка для этой проблемы: http://code.google.com/p/android/issues/detail?id=6191

Похоже, это началось с Android 2.1 и с тех пор присутствует во всех выпусках Android 2.x. Я не уверен, что проблема в Android 3.x или 4.x.

В любом случае, этот пост StackOverflow объясняет, как правильно решить проблему (это не выглядит актуальным по URL-адресу, но я обещаю, что это так)

Почему при скольжении клавиатуры происходит сбой моего приложения?

Джастин
источник
8

Я использовал блок try - catch, чтобы временно решить проблему.

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

Объявите получателя как null и затем поместите методы регистрации и отмены регистрации в onResume () и onPause () действия соответственно.

@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

Когда компонент пользовательского интерфейса, регистрирующий BR, уничтожается, BR также уничтожается. Следовательно, когда код отменяет регистрацию, возможно, BR уже был уничтожен.

Усанмаз
источник
0

Для всех, кто столкнется с этой проблемой, и они попробовали все, что было предложено, и ничего не работает, вот как я отсортировал свою проблему, вместо того, чтобы LocalBroadcastManager.getInstance(this).registerReceiver(...) сначала создать локальную переменную типа LocalBroadcastManager,

private LocalBroadcastManager lbman;

И использовал эту переменную для выполнения регистрации и отмены регистрации на широковещательном приемнике, то есть

lbman.registerReceiver(bReceiver);

и

lbman.unregisterReceiver(bReceiver);
нада
источник
0

Предположим, ваш broadcastReceiverопределяется следующим образом:

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

        // your code

    }
};

Если вы используете LocalBroadcastActivity, то отмените регистрацию следующим образом:

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

Если вы используете LocalBroadcastфрагмент, то отмените регистрацию следующим образом:

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

Если вы используете обычную трансляцию в Activity, вы отмените регистрацию следующим образом:

unregisterReceiver(broadcastReceiver);

Если вы используете обычную трансляцию во фрагменте, то отмените регистрацию следующим образом:

getActivity().unregisterReceiver(broadcastReceiver);
зишан
источник