Kesalahan: BinderProxy @ 45d459c0 tidak valid; Apakah aktivitas Anda berjalan?

143

Apa kesalahan ini ... saya belum menemukan diskusi tentang kesalahan ini di komunitas stackoverflow Detail: -

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)
VISHAL DAGA
sumber
periksa tautan ini: Android - [Menampilkan Dialog Dari Latar Belakang] ( dimitar.me/android-displaying-dialogs-from-background-threads )
Naveen
Tautan Anda serupa dengan jawaban yang diterima, tetapi jauh lebih baik. Terima kasih untuk itu
LuckyMalaka

Jawaban:

343

Ini kemungkinan besar terjadi karena Anda mencoba untuk menampilkan dialog setelah mengeksekusi utas latar belakang, sementara Aktivitas sedang dihancurkan.

Saya melihat kesalahan ini dilaporkan sesekali dari beberapa aplikasi saya ketika aktivitas yang memanggil dialog selesai karena beberapa alasan atau lainnya ketika mencoba menampilkan dialog. Inilah yang memecahkannya untuk saya:

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

Saya telah menggunakan ini untuk mengatasi masalah pada versi Android yang lebih lama selama beberapa tahun sekarang, dan belum melihat crash sejak itu.

DiscDev
sumber
1
Ini sebenarnya berhasil! tetapi adakah cara untuk membuka dialog meskipun itu terjadi? Saya tidak begitu yakin bagaimana mengelola dialog ketika ini terjadi. Ada saran? Terima kasih sebelumnya!
Carla Urrea Stabile
@CarlaStabile hai! Satu-satunya cara saya bisa memikirkan untuk menampilkan dialog ketika ini terjadi adalah jika Anda bisa mendapatkan Konteks yang valid untuk aktivitas yang tidak selesai - itu akan tergantung di mana Anda memanggil kode ini dan jika Anda memiliki cara untuk mengambil konteks dari aktivitas lain yang tidak selesai.
DiscDev
8
Terima kasih banyak! Bagi saya, crash (dengan pesan kesalahan di atas) akan terjadi ketika saya menekan tombol kembali, sebelum kotak Dialog muncul. Jadi kodenya akan berlanjut dan coba menunjukkannya, walaupun saya berada di aktivitas yang berbeda. Tetapi ini menghentikan tabrakan dan saya pergi ke aktivitas baru dengan mudah!
Azurespot
1
Ada banyak pertanyaan serupa, tetapi tidak satupun dari mereka yang menyarankan ini. Secara pribadi ini adalah satu-satunya solusi yang tepat untuk skenario saya.
fillobotto
apa versi kotlin untuk ini? akankah Finishing () cukup?
Alok Rajasukumaran
12

Saya menghadapi masalah yang sama dan menggunakan kode yang diusulkan oleh DiscDev di atas dengan perubahan kecil sebagai berikut:

if (!MainActivity.this.isFinishing()){
    alertDialog.show();
}
Hamza Polat
sumber
saya berubah karena rata-rata konteks (Aktivitas) adalah MainActivity.ini untuk kasus saya. Anda juga benar tentang tautan profil pengguna, tetapi saya pikir Anda dapat menemukannya di atas.
Hamza Polat
4

jika dialog mengatasi masalah ini karena utas Anda harus menjalankan ini pada utas UI seperti itu: -

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

            }
        });
Rahul Rao
sumber
2

Kesalahan ini terjadi ketika Anda menampilkan dialog untuk konteks yang tidak ada lagi.

Sebelum menelepon .show()periksa bahwa aktivitas / konteks belum selesai

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

Saya mengalami kesalahan ini ketika saya punya countDownTimerdi aplikasi saya. Itu metode memanggil GameOver di aplikasi saya sebagai

public void onFinish() {
     GameOver();
}

tetapi sebenarnya permainan bisa berakhir sebelum waktunya habis karena klik yang salah dari pengguna (itu adalah permainan mengklik). Jadi ketika saya melihat dialog Game Over setelah mis. 20 detik, saya lupa membatalkannya countDownTimerbegitu waktu habis, dialog muncul lagi. Atau jatuh dengan kesalahan di atas karena suatu alasan.

erdomester
sumber
1

Cara mengatasinya cukup sederhana. Cukup uji apakah Kegiatan sedang melewati tahap akhir sebelum menampilkan Dialog:

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

lihat lebih lanjut di sini

Diego Venâncio
sumber
1

Dalam kasus saya, masalahnya adalah yang Contextdisimpan sebagai referensi lemah di kelas yang meluas Handler. Kemudian saya lewat Messenger, yang membungkus pawang, melalui sebuah Intentke Service. Saya melakukan ini setiap kali aktivitas muncul di layar dalam onResume()metode.

Jadi seperti yang Anda pahami, Messenger diserialisasi bersama dengan bidangnya (termasuk konteks), karena itu adalah satu-satunya cara untuk melewatkan objek menggunakan Intent- untuk membuat cerita bersambung. Pada saat Messenger dilewatkan ke layanan, aktivitas itu sendiri masih belum siap untuk menampilkan dialog seperti di negara lain (dikatakan padaResume (), yang sama sekali berbeda dari ketika aktivitas sudah ada di layar). Jadi ketika messenger dideserialisasi, konteksnya masih pada keadaan melanjutkan, sementara aktivitas sebenarnya sudah di layar. Selain itu, deserialisasi mengalokasikan memori untuk objek baru, yang sama sekali berbeda dari yang asli.

Solusinya adalah hanya dengan mengikat ke layanan setiap kali Anda membutuhkannya dan mengembalikan binder yang memiliki metode seperti 'setMessenger (Messenger messenger)' dan menyebutnya, ketika Anda diikat ke layanan.

Turkhan Badalov
sumber
1

Saya mengatasi masalah ini dengan menggunakan WeakReference<Activity> sebagai konteks. Kecelakaan itu tidak pernah muncul lagi. Berikut ini contoh kode di Kotlin:

Kelas manajer dialog:

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

}

Dan Anda menampilkan dialog seperti ini:

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

Jika Anda ingin super-duper dilindungi dari crash. Alih-alih builder.create().show()menggunakan:

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

Inilah safeShowmetodenya:

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

Ini adalah metode serupa yang dapat Anda gunakan untuk mengabaikan dialog dengan aman:

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
                    }
                }
            }
        }
    }
Ivo Stoyanov
sumber
0

bagaimana dengan membuat Instance baru dari dialog yang ingin Anda panggil? Saya sebenarnya baru saja bertemu masalah yang sama, dan itulah yang saya lakukan. jadi daripada:

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

bagaimana dengan ini?

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

jadi daripada hanya memeriksa apakah aman atau tidak untuk menampilkan dialog, saya pikir itu jauh lebih aman jika kita hanya membuat contoh baru untuk menampilkan dialog.

Seperti saya, Dalam kasus saya, saya mencoba membuat satu instance (dari onCreate Fragment ) dan memanggil instance dari dialog tersebut di konten adapterList lain dan ini akan menghasilkan "is your activity running" - error . Saya pikir itu karena saya baru saja membuat satu instance (dari onCreate) dan kemudian dihancurkan, jadi ketika saya mencoba memanggilnya dari adapterList lain, saya memanggil dialog dari instance lama.

Saya tidak yakin apakah solusi saya ramah-memori atau tidak, karena saya belum mencoba profilnya, tetapi berfungsi (tentu saja, aman jika Anda tidak membuat terlalu banyak contoh)

Dan
sumber