수신자가 등록되지 않은 예외 오류입니까?


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. 귀하의 경우에는이 예외에 대해 특별한 try / catch를 입력하고 무시해야합니다 ( unregisterReceiver동일한 수신자에게 전화를 거는 횟수를 제어 할 수 없거나 제어하고 싶지 않다고 가정 ).


31
Android 플랫폼 자체에서이를 수행 할 수 있습니까? 위와 유사한 코드가 있었지만 서비스 등록을 취소하는 다른 코드가 전혀 없었고 동일한 예외가 발생합니다.
electrichead

2
저도 같은 문제 @electrichead을 가지고, 나는 .... 안드로이드 어딘가에 나를 위해 그 일을하지 않는 수신기들의 OnDestroy () 전에 등록 해제 될 위치를 확인할 수 없습니다
user1088166

@ user1088166, 활동에 대한 onStop () 메서드를 재정의하십시오. 거기에 try catch (IllegalArgumentException e)를 추가하고 의도적으로 브로드 캐스트 등록을 취소합니다. 도움이되는지 확인하세요 (3 년 된 댓글입니다 :))
Nactus

제 경우에 범인은 지연 초기화였습니다. 객체가 초기화되지 않았기 때문에 등록을 건너 뛰었 기 때문에 나중에 초기화되어 수신자 등록을 잊어 버렸습니다.
Boris Treukhov

@electrichead 아니오, 그것은 당신을 위해 그것을하지 않습니다. 올바른 방법을 선택하기 LocalBroadcastManager.getInstance(context).unregisterReceiver()context.unregisterReceiver()
만하면됩니다

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) 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) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:696) 원인 : java.lang.IllegalArgumentException : 수신기가 등록되지 않음 : com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584 at android.app.LoadedApk.forgetReceiverDispatcher (LoadedApk.java:769) at android.app.ContextImpl.unregisterReceiver (ContextImpl.java :1794) at 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) at 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를 더 잘 사용하십시오.
palindrom

2
Try catch 문이 더 좋습니다
Rowland

16

다른 답변에서 언급했듯이에 대한 각 호출 registerReceiver이 정확히 하나의 호출과 일치하지 않기 때문에 예외가 발생 합니다 unregisterReceiver. 왜 안돼?

An Activity은 항상 onDestroy모든 onCreate호출에 대해 일치하는 호출 이 있는 것은 아닙니다 . 시스템의 메모리가 부족하면을 호출하지 않고 앱이 제거 onDestroy됩니다.

풋하는 올바른 위치 registerReceiver호출은에 onResume전화하고, unregisterReceiveronPause. 이 통화 쌍은 항상 일치합니다. 자세한 내용은 활동 라이프 사이클 다이어그램을 참조하십시오. 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 2015 년

2
제거하는 데 약간의 CPU 사이클이 필요하기 때문에 유효하지 않은 핸들러를 던지는 예외를 남겨 두는 것이 정말로 제안됩니까?
Curmudgeonlybumbly

11

편집 : 이것은 inazaruk 및 electrichead에 대한 대답입니다 ... 나는 그들과 비슷한 문제를 겪었고 다음을 발견했습니다 ...

이 문제에 대한 오랜 버그가 있습니다. 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을 등록하는 UI 컴포넌트가 파괴되면 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);

LocalBroadcastFragment에서 사용 하는 경우 등록을 취소하는 방법은 다음과 같습니다.

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

활동에서 일반 방송을 사용하는 경우 등록을 취소하는 방법은 다음과 같습니다.

unregisterReceiver(broadcastReceiver);

프래그먼트에서 일반 브로드 캐스트를 사용하는 경우 등록을 취소하는 방법은 다음과 같습니다.

getActivity().unregisterReceiver(broadcastReceiver);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.