Помилка виключення у приймачі не зареєстрована?


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

будь-яка ідея, чому вони отримають цю помилку?

Відповіді:


207

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

 unregisterReceiver(batteryNotifyReceiver);

Якщо одержувач уже був незареєстрованим (напевно, у коді, який ви не включили до цієї публікації) або не був зареєстрований, тоді зателефонуйте unregisterReceiverкидати IllegalArgumentException. У вашому випадку вам потрібно просто поставити спеціальний спробу / ловити для цього винятку і проігнорувати його (припускаючи, що ви не можете чи не хочете контролювати кількість разів, коли ви викликаєте unregisterReceiverодного і того ж отримувача).


31
Чи можливо для цього сама платформа Android? Я мав подібний код до вищевказаного, але не маючи іншого коду, який би скасовував реєстрацію послуги, і я отримую той же виняток.
електричні

2
У мене така ж проблема @electrichead, я не можу побачити, де приймач буде незареєстрований перед onDestroy (), якщо Android десь не зробить це для мене ....
user1088166

@ user1088166, спробуйте змінити метод onStop () для вашої діяльності. Туди додайте спробу лову (IllegalArgumentException e) і навмисно скасуйте реєстрацію свого ефіру - подивіться, чи це допомагає (щойно помітив, що це трирічний коментар :))
Накт

У моєму випадку винуватцем була лінива ініціалізація - я пропустив реєстрацію, оскільки об’єкт не був ініціалізований, тому він був ініціалізований пізніше, і я забув реєстрацію приймача.
Борис Треухов

@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 / AndroidRunntime: ТОЧНЕ ВИКОНАННЯ: основний процес: 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@19538apapAt191938584 та at. 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 (Native Method) на 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.IllegalArgumentExcece : Одержувач не зареєстрований: com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584 за адресою android.app.LoadedApk.forgetReceiverDispatcher (LoadedApk.java:769) на android.app.ContextIpister (Excel).1794) на android.content.ContextWrapper.unregisterReceiver (ContextWrapper.javajanju10) на com.google.android.exoplayer.demo.player.PlayService.onDestroy (PlayService.javajanju42) на android.app.ActivityThread.handleSSpereShareleStop .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 (Native Method) на 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) 


Це справжня відповідь на цю проблему! Просто не забувайте, чи раніше ви зареєстрували глобальний або локальний приймач
user924

23

Використовуйте цей код скрізь для реєстрації реєстратора:

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

6
Ще зі мною трапляється. Краще використовувати пробний лов.
паліндром

2
Спробуйте заяву на вилов краще
Rowland Mtetezi

16

Як було сказано в інших відповідях, виняток кидається, оскільки кожен виклик registerReceiverне відповідає точно одному дзвінку unregisterReceiver. Чому ні?

У Activityне завжди є відповідність onDestroyдля кожного onCreateдзвінка. Якщо в системі не вистачає пам'яті, ваш додаток буде виселено без виклику onDestroy.

Правильне місце для registerReceiverдзвінка - у onResumeдзвінку та unregisterReceiverв onPause. Ця пара дзвінків завжди відповідає. Докладнішу інформацію див. У діаграмі життєвого циклу діяльності. 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);
}

Але це призведе до надмірних витрат на реєстрацію та реєстрацію ще багато разів. Я не впевнений у розмірі накладних витрат, але їх точно знайдуться.
Aman Deep Gautam

2
Ви дійсно пропонуєте залишити виняток, кинувши недійсний обробник на місце, тому що для його видалення коштуватиме кілька циклів процесора?
Примхливий, мабуть,

11

EDIT: Це відповідь для inazaruk та electrichead ... Я зіткнувся з подібним питанням до них і дізнався наступне ...

Тут існує давна помилка цієї проблеми: http://code.google.com/p/android/isissue/detail?id=6191

Схоже, він почався навколо Android 2.1 і з цього часу присутній у всіх версіях Android 2.x. Я не впевнений, чи все ж це проблема в Android 3.x або 4.x, хоча.

У будь-якому випадку ця публікація StackOverflow пояснює, як правильно вирішити проблему (вона не виглядає відповідною URL-адресою, але я обіцяю, що це є)

Чому слайд клавіатури виходить з ладу моєю програмою?


8

Я використовував блок "пробуючого", щоб тимчасово вирішити проблему.

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

Оголосіть приймач як недійсний, а потім введіть методи реєстрації та відреєстрації у 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

Коли компонент UI, який реєструє 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

    }
};

Якщо ви використовуєте LocalBroadcastв діяльності, тоді ви скасуєте реєстрацію:

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

Якщо ви використовуєте LocalBroadcastфрагмент, тоді ви скасуєте реєстрацію:

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

Якщо ви використовуєте звичайну трансляцію в рамках діяльності, тоді ви скасуєте реєстрацію:

unregisterReceiver(broadcastReceiver);

Якщо ви використовуєте звичайну трансляцію у Фрагменті, тоді ви скасуєте реєстрацію:

getActivity().unregisterReceiver(broadcastReceiver);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.