ข้อผิดพลาด: BinderProxy @ 45d459c0 ไม่ถูกต้อง กิจกรรมของคุณทำงานหรือไม่


144

ข้อผิดพลาดนี้คืออะไร ... ฉันไม่พบการสนทนาใด ๆ เกี่ยวกับข้อผิดพลาดนี้ในชุมชน stackoverflow โดยละเอียด: -

10-18 23:53:11.613: ERROR/AndroidRuntime(3197): Uncaught handler: thread main exiting due to uncaught exception
10-18 23:53:11.658: ERROR/AndroidRuntime(3197): android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@45d459c0 is not valid; is your activity running?
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.view.ViewRoot.setView(ViewRoot.java:468)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.view.Window$LocalWindowManager.addView(Window.java:424)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.app.Dialog.show(Dialog.java:239)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at com.vishal.contacte.Locationlistener$MyLocationListener.onLocationChanged(Locationlistener.java:86)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.location.LocationManager$ListenerTransport._handleMessage(LocationManager.java:179)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.location.LocationManager$ListenerTransport.access$000(LocationManager.java:112)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.location.LocationManager$ListenerTransport$1.handleMessage(LocationManager.java:128)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.os.Handler.dispatchMessage(Handler.java:99)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.os.Looper.loop(Looper.java:123)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.app.ActivityThread.main(ActivityThread.java:4363)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at java.lang.reflect.Method.invokeNative(Native Method)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at java.lang.reflect.Method.invoke(Method.java:521)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:862)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at dalvik.system.NativeStart.main(Native Method)

ตรวจสอบลิงค์นี้: Android - [แสดงไดอะล็อกจากหัวข้อพื้นหลัง] ( dimitar.me/android-displaying-dialogs-from-background-threads )
Naveen

ลิงก์ของคุณนั้นคล้ายคลึงกับคำตอบที่ยอมรับได้ แต่มันก็หมดอายุแล้วดีกว่ามาก ขอบคุณสำหรับสิ่งนั้น
LuckyMalaka


คำตอบ:


343

เหตุการณ์นี้น่าจะเกิดขึ้นเพราะคุณพยายามแสดงข้อความโต้ตอบหลังจากเรียกใช้เธรดพื้นหลังในขณะที่กิจกรรมกำลังถูกทำลาย

ฉันเห็นข้อผิดพลาดนี้รายงานเป็นระยะ ๆ จากแอพบางตัวของฉันเมื่อกิจกรรมที่เรียกกล่องโต้ตอบสิ้นสุดลงด้วยเหตุผลบางอย่างหรืออย่างอื่นเมื่อพยายามแสดงกล่องโต้ตอบ นี่คือสิ่งที่แก้ไขได้สำหรับฉัน:

if(!((Activity) context).isFinishing())
{
    //show dialog
}

ฉันใช้สิ่งนี้เพื่อแก้ไขปัญหาเกี่ยวกับ Android รุ่นเก่ามาหลายปีแล้วและยังไม่เห็นข้อผิดพลาดตั้งแต่นั้นมา


1
จริง ๆ แล้วจะหลอกลวง! แต่มีวิธีเปิดกล่องโต้ตอบแม้ว่าจะเกิดอะไรขึ้น? ฉันไม่แน่ใจจริงๆว่าจะจัดการไดอะล็อกได้อย่างไรเมื่อเกิดเหตุการณ์นี้ ข้อเสนอแนะใด ๆ ขอบคุณล่วงหน้า!
คาร์ล่า Urrea Stabile

@CarlaStabile สวัสดี! วิธีเดียวที่ฉันคิดว่าจะแสดงกล่องโต้ตอบเมื่อสิ่งนี้เกิดขึ้นถ้าคุณสามารถได้รับบริบทที่ถูกต้องสำหรับกิจกรรมที่ไม่เสร็จ - มันจะขึ้นอยู่กับที่คุณกำลังเรียกรหัสนี้และถ้าคุณมีวิธีในการเรียก บริบทจากกิจกรรมที่ไม่สิ้นสุด
DiscDev

8
ขอบคุณหนึ่งล้าน! สำหรับฉันความผิดพลาด (พร้อมข้อความแสดงข้อผิดพลาดด้านบน) จะเกิดขึ้นเมื่อฉันกดปุ่มย้อนกลับก่อนที่กล่องโต้ตอบจะปรากฏขึ้น ดังนั้นรหัสจะดำเนินต่อไปและพยายามที่จะแสดงมันแม้ว่าฉันจะอยู่ในกิจกรรมที่แตกต่างกัน แต่สิ่งนี้ก็หยุดความผิดพลาดและฉันก็ไปที่กิจกรรมใหม่อย่างง่ายดาย
Azurespot

1
มีคำถามที่คล้ายกันจำนวนมาก แต่ไม่มีใครเสนอคำถามนี้ โดยส่วนตัวนี่เป็นทางออกเดียวที่ถูกต้องสำหรับสถานการณ์ของฉัน
fillobotto

รุ่น kotlin สำหรับรุ่นนี้คืออะไร? จะเสร็จสิ้น () จะเพียงพอหรือไม่
Alok Rajasukumaran

12

ฉันประสบปัญหาเดียวกันและใช้รหัสที่เสนอโดยDiscDevด้านบนด้วยการเปลี่ยนแปลงเล็กน้อยดังนี้:

if (!MainActivity.this.isFinishing()){
    alertDialog.show();
}

ฉันเปลี่ยนเพราะค่าเฉลี่ยบริบท (กิจกรรม) คือ MainActivity.this สำหรับกรณีของฉัน นอกจากนี้คุณมีสิทธิ์เกี่ยวกับลิงค์โปรไฟล์ผู้ใช้ แต่ฉันคิดว่าคุณสามารถค้นหาได้ด้านบน
Hamza Polat

4

ถ้าไดอะล็อกทำการ trowing ปัญหานี้เนื่องจากเธรดคุณควรรันบนเธรด UI ดังนี้: -

runOnUiThread(new Runnable() {
            @Override
            public void run() {
                dialog.show();

            }
        });

2

ข้อผิดพลาดนี้เกิดขึ้นเมื่อคุณแสดงกล่องโต้ตอบสำหรับบริบทที่ไม่มีอยู่อีกต่อไป

ก่อนที่จะโทร.show()ตรวจสอบว่ากิจกรรม / บริบทไม่จบ

if (!(context instanceof Activity && ((Activity) context).isFinishing())) {
    alert.show();
}

1

ฉันพบข้อผิดพลาดนี้เมื่อฉันมีcountDownTimerในแอพของฉัน มีวิธีเรียก GameOver ในแอพของฉันเป็น

public void onFinish() {
     GameOver();
}

แต่ที่จริงแล้วเกมอาจจบลงก่อนเวลาจะถึงกำหนดเนื่องจากผู้ใช้คลิกผิด (เป็นเกมคลิก) ดังนั้นเมื่อฉันดูที่ไดอะล็อก Game Over หลังจากเช่น 20 วินาทีฉันลืมยกเลิกcountDownTimerดังนั้นเมื่อเวลาหมดลงไดอะล็อกจะปรากฏขึ้นอีกครั้ง หรือชนกับข้อผิดพลาดดังกล่าวข้างต้นด้วยเหตุผลบางอย่าง


1

การแก้ไขปัญหานี้ค่อนข้างง่าย เพียงทดสอบว่ากิจกรรมกำลังดำเนินการเสร็จสิ้นก่อนที่จะแสดงกล่องโต้ตอบหรือไม่:

  private Handler myHandler = new Handler() {
  @Override
  public void handleMessage(Message msg) {
    switch (msg.what) {
      case DISPLAY_DLG:
        if (!isFinishing()) {
        showDialog(MY_DIALOG);
        }
      break;
    }
  }
};

ดูเพิ่มเติมที่นี่


1

ในกรณีของปัญหาคือการที่ถูกเก็บไว้เป็นข้อมูลอ้างอิงที่อ่อนแอในชั้นเรียนที่ขยายContext Handlerจากนั้นผมกำลังเดินผ่านMessengerที่ wraps จัดการผ่านไปIntent Serviceฉันทำสิ่งนี้ทุกครั้งที่มีกิจกรรมปรากฏบนหน้าจอตามonResume()วิธีการ

ดังที่คุณเข้าใจ Messenger ได้รับการจัดลำดับพร้อมกับฟิลด์ (รวมถึงบริบท) เนื่องจากเป็นวิธีเดียวที่จะส่งผ่านวัตถุโดยใช้Intent- เพื่อทำให้เป็นอันดับ ในขณะนั้นเมื่อ Messenger ถูกส่งไปยังบริการกิจกรรมยังไม่พร้อมที่จะแสดงข้อความโต้ตอบเนื่องจากอยู่ในสถานะอื่น (กล่าวว่า onResume () ซึ่งแตกต่างจากกิจกรรมเมื่ออยู่บนหน้าจออยู่แล้ว) ดังนั้นเมื่อร่อซู้ลถูกยกเลิกการใช้งานบริบทยังคงอยู่ในสถานะที่กลับมาทำงานต่อในขณะที่กิจกรรมนั้นอยู่บนหน้าจอจริง นอกจากนี้การดีซีเรียลไลเซชันจะจัดสรรหน่วยความจำสำหรับวัตถุใหม่ซึ่งแตกต่างไปจากเดิมอย่างสิ้นเชิง

การแก้ปัญหาคือการผูกกับบริการทุกครั้งที่คุณต้องการและส่งคืนเครื่องผูกที่มีวิธีการเช่น 'setMessenger (Messenger messenger)' และเรียกมันว่าเมื่อคุณถูกผูกไว้กับบริการ


1

ฉันแก้ปัญหานี้โดยใช้WeakReference<Activity>เป็นบริบท ความผิดพลาดไม่เคยปรากฏขึ้นอีกครั้ง นี่คือตัวอย่างรหัสใน Kotlin:

คลาสผู้จัดการไดอะล็อก:

class DialogManager {

        fun showAlertDialog(weakActivity: WeakReference<Activity>) {
            val wActivity = weakActivity.get()
            wActivity?.let {
                val builder = AlertDialog.Builder(wActivity, R.style.MyDialogTheme)
                val inflater = wActivity.layoutInflater
                val dialogView = inflater.inflate(R.layout.alert_dialog_info, null)
                builder.setView(dialogView)

                // Set your dialog properties here. E.g. builder.setTitle("MyTitle")

                builder.create().show()
            }
         }

}

และคุณแสดงข้อความแบบนี้:

 val dialogManager = DialogManager()
 dialogManager.showAlertDialog(WeakReference<Activity>(this@MainActivity))

หากคุณต้องการได้รับการปกป้องอย่างยอดเยี่ยมจากการล่ม แทนที่จะbuilder.create().show()ใช้:

val dialog = builder.create()
safeShow(weakActivity, dialog)

นี่คือsafeShowวิธีการ:

private fun safeShow(weakActivity: WeakReference<Activity>, dialog: AlertDialog?) {
        val wActivity = weakActivity.get()
        if (null != dialog && null != wActivity) {
            // Api >=17
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                if (!dialog.isShowing && !(wActivity).isFinishing && !wActivity.isDestroyed) {
                    try {
                        dialog.show()
                    } catch (e: Exception) {
                        //Log exception
                    }
                }
            } else {

                // Api < 17. Unfortunately cannot check for isDestroyed()
                if (!dialog.isShowing && !(wActivity).isFinishing) {
                    try {
                        dialog.show()
                    } catch (e: Exception) {
                        //Log exception
                    }
                }
            }
        }
    }

นี่เป็นวิธีการที่คล้ายกันซึ่งคุณสามารถใช้เพื่อปิดการโต้ตอบอย่างปลอดภัย:

private fun safeDismissAlertDialog(weakActivity: WeakReference<Activity>, dialog: AlertDialog?) {
        val wActivity = weakActivity.get()
        if (null != dialog && null != wActivity) {
            // Api >=17
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                if (dialog.isShowing && !wActivity.isFinishing && !wActivity.isDestroyed) {
                    try {
                        dialog.dismiss()
                    } catch (e: Exception) {
                        //Log exception
                    }
                }
            } else {

                // Api < 17. Unfortunately cannot check for isDestroyed()
                if (!dialog.isShowing && !(wActivity).isFinishing) {
                    try {
                        dialog.dismiss()
                    } catch (e: Exception) {
                        //Log exception
                    }
                }
            }
        }
    }

0

วิธีการสร้างอินสแตนซ์ใหม่ของกล่องโต้ตอบนั้นที่คุณต้องการโทรหา ที่จริงฉันเพิ่งพบปัญหาเดียวกันและนั่นคือสิ่งที่ฉันทำ ดังนั้นมากกว่า:

if(!((Activity) context).isFinishing())
{
    //show dialog
}

แล้วเรื่องนี้ล่ะ

 YourDialog mDialog = new YourDialog();
 mDialog1.show(((AppCompatActivity) mContext).getSupportFragmentManager(), "OrderbookDialog");
                        }

ดังนั้นแทนที่จะแค่ตรวจสอบว่าปลอดภัยหรือไม่เพื่อแสดงกล่องโต้ตอบฉันคิดว่ามันปลอดภัยกว่าถ้าเราเพิ่งสร้างอินสแตนซ์ใหม่เพื่อแสดงกล่องโต้ตอบ

เหมือนผมในกรณีของฉันฉันพยายามที่จะสร้างอินสแตนซ์ (จากส่วน onCreate ) และโทรตัวอย่างของการโต้ตอบเหล่านั้นในเนื้อหาของผู้อื่นadapterListและนี้จะส่งผลให้"เป็นกิจกรรมของคุณทำงาน" - ข้อผิดพลาด ฉันคิดว่าเป็นเพราะฉันเพิ่งสร้างหนึ่งอินสแตนซ์ (จาก onCreate) และจากนั้นมันจะถูกทำลายดังนั้นเมื่อฉันพยายามโทรจากอะแดปเตอร์อื่นฉันจะเรียกไดอะล็อกจากอินสแตนซ์เก่า

ฉันไม่แน่ใจว่าโซลูชันของฉันเป็นมิตรกับหน่วยความจำหรือไม่เพราะฉันไม่ได้พยายามโพรไฟล์ แต่ใช้งานได้ (แน่นอนว่ามันปลอดภัยถ้าคุณไม่สร้างอินสแตนซ์มากเกินไป)

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