show dialog时crash Unable to add window -- token android.os.BinderProxy@77644c1 is not valid;

博客指出在显示dialog时发生崩溃,堆栈显示是android.view.WindowManager$BadTokenException,原因可能是token无效,需检查activity是否finish掉。处理措施是在show前判断!Activity.isFinishing()。

在显示dialog的时候 发生崩溃

堆栈如下:

android.view.WindowManager$BadTokenException    Unable to add window -- token android.os.BinderProxy@77644c1 is not valid; is your activity running?
ViewRootImpl.java    816
android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@77644c1 is not valid; is your activity running?
    at android.view.ViewRootImpl.setView(ViewRootImpl.java:816)
    at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:381)
    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:94)
    at android.app.Dialog.show(Dialog.java:364)

检查activity是否finish掉了。

处理措施:

在show前判断 !Activity.isFinishing()

这个错误: ``` Unable to add window -- token android.os.BinderProxy@... is not valid; is your activity running? ``` 是 Android 开发中常见的运行异常,通常发生在你试图显示一个 `Dialog`(比如 `AlertDialog`),但此 **上下文(Context)已经无效** 或 **Activity 已经 finish 了**。 --- ## 🔍 错误原因 Android 的 `WindowManager` 需要一个有效的 `token` 来将窗口添加到屏幕上。如果你使用的 `Context` 是一个已经销毁的 Activity,或者你在非主线程操作 UI,就会导致这个错误。 ### 常见场景如下: 1. 在已销毁的 Activity 中调用 `dialog.show()`; 2. 在异步任务(如网络请求、Handler)中尝试弹出 Dialog,但此 Activity 已关闭; 3. 使用了 ApplicationContext 显示 Dialog(ApplicationContext 不适合用来显示 Dialog); 4. 多线程中未检查 Context 是否有效就直接 show dialog--- ## ✅ 解决方案 ### ✅ 方案一:在显示 Dialog 前判断 Activity 是否处于活跃状态 ```java if (context instanceof Activity && !((Activity) context).isFinishing()) { alert.show(); } else { // Log or ignore } ``` 修改你的 `showConfirmDialog()` 方法开头部分如下: ```java public static void showConfirmDialog(Context context, String title, String content, int type) { if (!(context instanceof Activity) || ((Activity) context).isFinishing()) { // 避免在无效的上下文中创建 Dialog return; } builder = new AlertDialog.Builder(context); alert = builder.create(); if (!((Activity) context).isDestroyed()) { // API >= 24 alert.show(); } else { return; } // ... 后续代码不变 ... } ``` > 注意:`isFinishing()` 和 `isDestroyed()` 可以防止在 Activity 关闭状态下显示 Dialog--- ### ✅ 方案二:使用 Lifecycle-aware 组件(推荐用于现代架构) 如果你使用的是 `androidx.lifecycle`,可以考虑使用 `LifecycleObserver` 来监听生命周期,在合适的时机才显示 Dialog。 不过对于简单使用来说,上面的 `isFinishing()` 判断已经足够。 --- ### ✅ 方案三:避免在非主线程更新 UI / 显示 Dialog 确保你在主线程中执行 `alert.show()`。例如: ```java new Handler(Looper.getMainLooper()).post(() -> { if (!((Activity) context).isFinishing()) { alert.show(); } }); ``` --- ## ✅ 完整修复示例 ```java public static void showConfirmDialog(Context context, String title, String content, int type) { if (!(context instanceof Activity) || ((Activity) context).isFinishing()) { // 上下文无效或 Activity 已结束,不显示 Dialog return; } Activity activity = (Activity) context; builder = new AlertDialog.Builder(context); alert = builder.create(); alert.show(); //引入布局 view_custom = LayoutInflater.from(context).inflate(R.layout.alert_dialog,null,false); tv_dialog_title = view_custom.findViewById(R.id.title); tv_dialog_title.setText(title); tv_dialog_content = view_custom.findViewById(R.id.content); // ... 其他初始化代码 ... alert.getWindow().setContentView(view_custom); alert.getWindow().setBackgroundDrawableResource(R.drawable.dialog_rounded_background); // 确保按钮在文字显示完再显示 final int[] index = {0}; StringBuilder stringBuilder = new StringBuilder(); handler = new Handler(Looper.getMainLooper()); runnable = new Runnable() { @Override public void run() { if (index[0] < content.length()) { stringBuilder.append(content.charAt(index[0])); tv_dialog_content.setText(stringBuilder.toString()); addNeonEffect(tv_dialog_content); index[0]++; handler.postDelayed(this, 100); } else { view_custom.findViewById(R.id.comfirm_btn).setVisibility(View.VISIBLE); view_custom.findViewById(R.id.cancel_btn).setVisibility(View.VISIBLE); } } }; handler.post(runnable); // 设置按钮点击事件等... } ``` --- ## 🛠️ 补充建议 | 场景 | 推荐做法 | |------|----------| | 异步加载后显示 Dialog | 使用 WeakReference<Activity> + isFinishing() 检查 | | Dialog 显示前判断 Context | 使用 `context instanceof Activity && !((Activity)context).isFinishing()` | | 多个 Dialog 连续显示 | 使用队列管理 Dialog 展示逻辑 | | Dialog 泄漏问题 | 在 onDestroy 中 dismiss dialog 并取消所有 pending handler | --- ##
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值