Помилка: 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
Це насправді робить трюк! але чи є спосіб відкрити діалогове вікно, навіть якщо це трапиться? Я не дуже впевнений, як керувати діалоговим вікном, коли це станеться. Будь-які пропозиції? Спасибі заздалегідь!
Carla Urrea Stabile

@CarlaStabile привіт! Єдиний спосіб я думаю про те, щоб показати діалогове вікно, коли це станеться, було б, якщо ви можете отримати дійсний контекст для діяльності, яка не закінчується - це залежатиме від того, де ви викликаєте цей код, і чи є у вас спосіб отримати контекст з іншої, незавершеної діяльності.
DiscDev

8
Завдяки мільйонів! Для мене збій (з повідомленням про помилку вище) відбудеться, коли я натиснув кнопку назад, перш ніж з'явиться діалогове вікно. Тож код продовжував би і намагався його показати, хоч я і займався іншою діяльністю. Але це зупинило аварію, і я з легкістю пішов на нову діяльність!
Azurespot

1
Є багато подібних питань, але в жодному з них цього не було запропоновано. Особисто це було єдино правильне рішення для мого сценарію.
fillobotto

що для цього версія kotlin? буде достатньо Fininishing ()?
Алок Раджасукумаран

12

Я зіткнувся з тією ж проблемою і використав код, запропонований DiscDev вище, з незначними змінами:

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

я змінився, оскільки серед контексту (Activity) середнього значення було MainActivity.this для мого випадку. Також ви маєте рацію щодо посилання на профіль користувача, але я подумав, що ви можете знайти його вище.
Хамза Полат

4

якщо діалогове вікно усуває цю проблему через нитку, ви повинні запустити це на потоці інтерфейсу так: -

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, що загортає обробник, через a Intentдо a Service. Я робив це щоразу, коли активність з'являлася на екрані в onResume()методі.

Отже, як ви розумієте, Messenger був серіалізований разом зі своїми полями (включаючи контекст), тому що це єдиний спосіб передачі об'єктів за допомогою Intent- їх серіалізація. У той момент, коли Месенджер був переданий до сервісу, сама активність ще не була готова до показу діалогів, як це знаходиться в іншому стані (про що говорять onResume (), що абсолютно відрізняється від того, коли активність вже на екрані). Тож, коли десаріалізований месенджер, контекст все ще знаходився у відновлюваному стані, тоді як активність фактично вже була на екрані. Більше того, десеріалізація виділяє пам'ять для нового об'єкта, який повністю відрізняється від початкового.

Рішення полягає лише в тому, щоб прив’язати до служби кожен раз, коли вам це потрібно, і повернути зв'язувальний пристрій, який має метод типу "setMessenger (Messenger messenger)" і викликати його, коли вас прив'язують до служби.


1

Я вирішую цю проблему, використовуючи WeakReference<Activity>як контекст. Збій більше ніколи не з’явився. Ось зразок коду в Котліні:

Клас менеджера діалогів:

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), а потім він руйнується, тому, коли я намагався викликати його з іншого адаптаційного списку, я викликав діалог зі старого примірника.

Я не впевнений, чи моє рішення зручне для пам'яті чи ні, тому що я не намагався його профілювати, але він працює (ну, безумовно, це безпечно, якщо ви не створите занадто багато примірників)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.