レシーバーが登録されていない例外エラー?


112

私の開発者コンソールでは、私が持っているどの電話でも再現できないエラーが報告され続けています。1人が、私のバッテリーサービスの設定画面を開こうとしたときにメッセージが表示されるというメッセージを残しました。エラーからわかるように、受信者が登録されていません。

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

レシーバーがすでに登録解除されている(おそらくこの投稿に含まれていないコードに含まれている)か、登録されていない場合は、unregisterReceiverthrowsを呼び出しますIllegalArgumentException。あなたの場合、あなたはこの例外のために特別なtry / catchを入れてそれを無視する必要があります(unregisterReceiver同じレシーバーで呼び出す回数を制御できないか、したくないと仮定した場合)。


31
Androidプラットフォーム自体がこれを行うことは可能ですか?上記と同様のコードを使用しましたが、サービスを登録解除する他のコードがまったくなく、同じ例外が発生します。
電気

2
私は@electricheadで同じ問題を抱えています
。Androidが

@ user1088166、アクティビティのonStop()メソッドをオーバーライドしてみてください。そこにtry catch(IllegalArgumentException e)を追加し、意図的にブロードキャストの登録を解除します-それが役立つかどうかを確認します(これは3年前のコメントです:))
Nactus

私の場合、犯人は怠惰な初期化でした-オブジェクトが初期化されていなかったため、登録をスキップしました。そのため、後で初期化され、受信者の登録を忘れていました。
ボリストロイホフ2017年

@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 / AndroidRuntime:FATAL EXCEPTION:main Process:com.jialan.guangdian.view、PID:19064 java.lang.RuntimeException:Unable to stop service com.google.android.exoplayer.demo.player.PlayService@141ba331:java.lang.IllegalArgumentException:受信者が登録されていません:com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584 at android.app.ActivityThread。 handleStopService(ActivityThread.java:2941)at android.app.ActivityThread.access $ 2200(ActivityThread.java:148)android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1395)at android.os.Handler.dispatchMessage(Handler.java:102)at android.os.Looper.loop(Looper.java:135)at android.app.ActivityThread.main(ActivityThread.java:5310)at java.lang.reflect.Method.invoke(Native Method)at java.lang.reflect.Method.invoke(Method.java:372)com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:901)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)発生原因:java.lang.IllegalArgumentException :レシーバーが登録されていません:com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584(android.app.LoadedApk.forgetReceiverDispatcher(LoadedApk.java:769)at android.app.ContextImpl.unregisterReceiver(ContextImpl.java:1794)android.content.ContextWrapper.unregisterReceiver(ContextWrapper.java:510)at com.google.android.exoplayer.demo.player.PlayService.onDestroy(PlayService.java:542)at android.app.ActivityThread.handleStopService(ActivityThread .java:2924)android.app.ActivityThread.access $ 2200(ActivityThread.java:148)at android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1395)at android.os.Handler.dispatchMessage(Handler.java:102)at android.os.Looper.loop(Looper.java:135)at android.app.ActivityThread.main(ActivityThread.java:5310)at java。 lang.reflect.Method.invoke(Native Method)at java.lang.reflect.Method.invoke(Method.java:372)at com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:901)com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)で 


これがこの問題の正解です。以前にグローバルレシーバーまたはローカルレシーバーを登録したかどうかを忘れないでください
user924

23

unregisterReceiverのどこでもこのコードを使用します。

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

6
まだ私に起こります。try-catchを使用することをお勧めします。
パリンドローム

2
キャッチステートメントを試してみてください
Rowland Mtetezi

16

他の回答で述べたように、への各呼び出しがへのregisterReceiver1つの呼び出しと一致しないため、例外がスローされ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);
}

ただし、これにより、登録と登録解除のオーバーヘッドがさらに多く発生します。オーバーヘッドの量はわかりませんが、確かにいくつかあります。
アマンディープゴータム

2
無効なハンドラーをスローする例外をそのままにしておくと、それを削除するためにいくつかのCPUサイクルがかかるので、本当に提案しているのですか
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として宣言してから、registerメソッドとunregisterメソッドをアクティビティの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を登録するUIコンポーネントが破棄されると、BRも破棄されます。したがって、コードが登録解除されると、BRはすでに破棄されている可能性があります。


0

この問題にLocalBroadcastManager.getInstance(this).registerReceiver(...) 遭遇し、提案されたすべてを試しても何も機能しない人のために、これは私が最初にLocalBroadcastManagerタイプのローカル変数を作成する代わりに、問題をソートする方法です、

private LocalBroadcastManager lbman;

そして、この変数を使用して、broadcastreceiverでの登録と登録解除を実行しました。

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);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.