错误: BinderProxy@45d459c0无效; 您的活动正在运行吗?

这个错误是什么... ... 我在 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)
110080 次浏览

这种情况最有可能发生,因为您正试图在后台线程执行后显示一个对话框,而 Activity 正在被销毁。

当调用对话框的活动由于某种原因结束时,当它试图显示一个对话框时,我看到我的一些应用程序偶尔报告这个错误。下面是我的答案:

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

几年来,我一直在用这个来解决老版本 Android 的问题,从那以后就再也没见过这次崩溃。

2021年最新情况

在一些评论中已经指出,盲目地将 Context转换为 Activity是不好的。我同意!

如今,当我在 Fragment中编写类似的代码时(在提供原始答案的8年多之后) ,我会这样做:

if (!requireActivity().isFinishing) {
// show dialog
}

主要的教训是,试图显示一个对话框或更新任何 UI 后,宿主 Activity已被关闭将导致崩溃。请尽可能避免这种情况发生,在活动被关闭时杀死后台线程,或者至少使用这里的答案来阻止应用程序崩溃。

我遇到这个错误时,我有一个 countDownTimer在我的应用程序。它在我的应用程序中有一个调用 GameOver 的方法

public void onFinish() {
GameOver();
}

但实际上,由于用户的错误点击(这是一个点击游戏) ,游戏可能在时间到之前就结束了。所以当我看到20秒后的游戏结束对话框时,我忘了取消 countDownTimer,所以一旦时间到了,对话框又出现了。或者由于以上错误而崩溃。

我遇到了同样的问题,使用了上面 DiscDev提出的代码,做了以下小小的改动:

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

解决办法很简单。在显示对话框之前,只需要测试活动是否正在完成它的最后阶段:

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

详情请参阅 给你

在我的例子中,问题是 Context被保留为扩展 Handler的类中的弱引用。然后我传递 Messenger,它包装了处理程序,通过一个 Intent到一个 Service。在 onResume()方法中,每次活动出现在屏幕上时,我都这样做。

因此,正如您所理解的,Messenger 是连同它的字段(包括上下文)一起序列化的,因为这是使用 Intent传递对象的唯一方法——序列化它们。当 Messenger 被传递到服务时,活动本身还没有准备好显示对话框,因为它处于另一种状态(在 Resume ()上说,这与活动已经显示在屏幕上的情况完全不同)。因此,当信使被反序列化时,上下文仍处于恢复状态,而活动实际上已经在屏幕上了。此外,反序列化为新对象分配内存,这与原始对象完全不同。

解决方案只是在每次需要时绑定到服务,然后返回一个具有类似“ setMessenger (Messenger)”方法的绑定器,并在绑定到服务时调用它。

如果由于线程的原因,对话框抛出了这个问题,你应该像这样在 UI 线程上运行:-

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


}
});

我通过使用 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
}
}
}
}
}

当显示不再存在的上下文的对话框时,会发生此错误。

在调用 .show()之前,检查活动/上下文是否未完成

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

为要调用的对话框创建一个新实例如何?其实我也遇到了同样的问题,这就是我的工作。而不是:

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

这个怎么样?

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

因此,与其仅仅检查显示对话框是否安全,我认为如果我们只创建一个 新的例子来显示对话框会安全得多。

像我一样,在我的例子中,我尝试创建一个实例(从 碎片 OnCreate) ,并在 适配器列表的另一个内容中调用这些对话框的实例,这将导致 “您的活动正在运行”-错误。我认为这是因为我只创建了一个实例(从 onCreate) ,然后它就被销毁了,所以当我试图从另一个 适配器列表调用它时,我从旧的实例调用对话框。

我不确定我的解决方案是否对内存友好,因为我还没有尝试对它进行概要分析,但它是有效的 (当然,如果不创建太多实例,这是安全的)

在 Kotlin

if (!(context is Activity && context.isFinishing)) {
pausingDialog!!.show()
}