ผู้รับไม่ได้ลงทะเบียนข้อผิดพลาดข้อยกเว้น?


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 จะทำเช่นนี้ ฉันมีรหัสที่คล้ายกันกับข้างต้น แต่ไม่มีรหัสอื่นเลยที่จะยกเลิกการลงทะเบียนบริการและฉันก็ได้รับข้อยกเว้นเหมือนกัน
ช่างไฟฟ้า

2
ฉันมีปัญหาเดียวกัน @electrichead ฉันไม่เห็นว่าผู้รับจะยกเลิกการลงทะเบียนก่อน onDestroy () เว้นแต่ Android จะทำเพื่อฉันที่ไหนสักแห่ง ....
user1088166

@ user1088166 ลองลบล้างเมธอด onStop () สำหรับกิจกรรมของคุณ ในนั้นให้เพิ่ม try catch (IllegalArgumentException e) และยกเลิกการลงทะเบียนการออกอากาศของคุณโดยเจตนา - ดูว่าช่วยได้หรือไม่ (เพิ่งสังเกตว่านี่เป็นความคิดเห็นที่มีอายุ 3 ปี :))
Nactus

ในกรณีของฉันผู้กระทำผิดคือการเริ่มต้นที่ขี้เกียจ - ฉันข้ามการลงทะเบียนเนื่องจากไม่ได้เริ่มต้นอ็อบเจ็กต์ดังนั้นจึงเริ่มต้นในภายหลังและฉันลืมการลงทะเบียนผู้รับ
Boris Treukhov

@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: ไม่สามารถหยุดบริการได้ 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 (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.IllegalArgumentException : ผู้รับไม่ได้ลงทะเบียน: com.google.android.exoplayer.demo.player.PlayService$PlayStatusReceiver@19538584 ที่ android.app.LoadedApk.forgettableReceiverDispatcher (LoadedApk.java:769) ที่ android.app.ContextImpl.unregisterReceiver (ContextImpl.java: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 (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

ใช้รหัสนี้ทุกที่สำหรับ unregisterReceiver:

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

6
ยังคงเกิดขึ้นกับฉัน ลองจับดูดีกว่า
palindrom

2
ลองใช้คำสั่ง catch จะดีกว่า
Rowland Mtetezi

16

ตามที่ระบุไว้ในคำตอบอื่น ๆ ยกเว้นจะถูกโยนทิ้งเพราะการโทรแต่ละครั้งจะไม่ได้ถูกจับคู่โดยตรงโทรหนึ่งไปregisterReceiver unregisterReceiverทำไมจะไม่ล่ะ?

An 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
คุณแนะนำให้ทิ้งข้อยกเว้นในการทิ้งตัวจัดการที่ไม่ถูกต้องเพราะจะต้องเสียค่าใช้จ่ายบางรอบของ 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 จากนั้นใส่ register และ unregister method ใน 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ใน Fragment นี่คือวิธีที่คุณจะยกเลิกการลงทะเบียน:

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

หากคุณใช้การออกอากาศปกติในกิจกรรมนี่คือวิธีที่คุณจะยกเลิกการลงทะเบียน:

unregisterReceiver(broadcastReceiver);

หากคุณใช้การออกอากาศปกติใน Fragment นี่คือวิธีที่คุณจะยกเลิกการลงทะเบียน:

getActivity().unregisterReceiver(broadcastReceiver);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.