Ошибка: BinderProxy @ 45d459c0 недействителен; ваша деятельность идет?

149

Что это за ошибка ... Я не нашел обсуждения этой ошибки в сообществе 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

Ответы:

352

Скорее всего, это происходит из-за того, что вы пытаетесь показать диалог после выполнения фонового потока, когда Activity уничтожается.

Время от времени я получал сообщения об этой ошибке из некоторых моих приложений, когда действие, вызывающее диалог, по той или иной причине заканчивалось, когда оно пыталось показать диалог. Вот что для меня решило:

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

Я уже несколько лет использую это, чтобы обойти проблему в старых версиях Android, и с тех пор не видел сбоев.

DiscDev
источник
1
Это действительно трюк! но есть ли способ открыть диалог, даже если это произойдет? Я не совсем уверен, как управлять диалогом, когда это происходит. Какие-либо предложения? Заранее спасибо!
Карла Урреа Стабиле
@CarlaStabile привет! Единственный способ показать диалоговое окно, когда это произойдет, - это получить действительный контекст для действия, которое не завершается - это будет зависеть от того, где вы вызываете этот код и есть ли у вас способ получить контекст из другого, незавершенного действия.
DiscDev
8
Бесконечно благодарен! Для меня сбой (с сообщением об ошибке выше) произойдет, когда я нажму кнопку «Назад» до того, как появится диалоговое окно. Таким образом, код продолжался и пытался показать его, хотя я был в другой деятельности. Но это остановило сбой, и я с легкостью перешел к новому занятию!
Azurespot
1
Подобных вопросов много, но ни в один из них такого не предлагалось. Лично это было единственно правильным решением для моего сценария.
fillobotto
какая для этого версия котлина? будет достаточно isFinishing ()?
Алок Раджасукумаран
12

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

if (!MainActivity.this.isFinishing()){
    alertDialog.show();
}
Хамза Полат
источник
Я изменился, потому что средним значением контекста (Activity) было MainActivity. это для моего случая. Также вы правы относительно ссылки на профиль пользователя, но я подумал, что вы можете найти ее выше.
Хамза Полат
4

если диалог вызывает эту проблему из-за потока, вы должны запустить его в потоке пользовательского интерфейса следующим образом: -

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

            }
        });
Рахул Рао
источник
2

Эта ошибка возникает, когда вы показываете диалог для контекста, который больше не существует.

Перед вызовом .show()убедитесь, что действие / контекст не завершаются

if (!(context instanceof Activity && ((Activity) context).isFinishing())) {
    alert.show();
}
akhilesh0707
источник
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обработчик через объект Intenta Service. Я делал это каждый раз, когда действие появлялось на экране в onResume()методе.

Итак, как вы понимаете, Messenger был сериализован вместе со своими полями (включая контекст), потому что это единственный способ передавать объекты, используя Intent - для их сериализации. В тот момент, когда Messenger был передан в службу, само действие еще не было готово для отображения диалогов, поскольку оно находится в другом состоянии (как говорится, 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 ) и вызвать экземпляр этого диалога в другом содержимом адаптера, и это приведет к ошибке «выполняется ли ваша активность» . Я думал, что это потому, что я просто создаю один экземпляр (из onCreate), а затем он уничтожается, поэтому, когда я попытался вызвать его из другого адаптера, я вызвал диалог из старого экземпляра.

Я не уверен, подходит ли мое решение для памяти или нет, потому что я не пробовал его профилировать, но оно работает (ну, конечно, это безопасно, если вы не создаете слишком много экземпляров)

Дэн
источник
0

В Котлине

if (!(context is Activity && context.isFinishing)) {
            pausingDialog!!.show()
        }
Сандип Парик
источник