应用运行中突发崩溃,报WindowManager$BadTokenException错误求助
WindowManager$BadTokenException(Toast崩溃)问题 兄弟,你遇到的这个崩溃我太熟了——看调用栈明显是Toast搞的鬼!android.view.WindowManager$BadTokenException本质就是:你要显示的Toast找不到有效的Activity窗口依附了,那个BinderProxy@aba286f就是已经失效的Activity窗口令牌。
问题根源
从调用栈里的Toast$TN.handleShow能看出来,你肯定是在Activity已经销毁之后(比如调用了finish()、屏幕旋转重建前、App后台太久被系统回收),还在尝试显示Toast。这时候Activity的窗口已经不存在了,系统当然不让你添加新的Toast窗口。
具体解决方案
我给你几个实用的解决办法,按场景选就行:
1. 显示Toast前先检查Activity状态
最直接的方式:在调用Toast.show()之前,先确认Activity还活着:
// 在Activity里直接用 if (!isFinishing() && !isDestroyed()) { Toast.makeText(this, "你的提示内容", Toast.LENGTH_SHORT).show(); }
如果是在Fragment里,记得先判空Activity:
Activity activity = getActivity(); if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) { Toast.makeText(activity, "Fragment里的提示", Toast.LENGTH_SHORT).show(); }
2. 用Application Context显示Toast(简单但有局限)
如果你的Toast不需要自定义位置,也可以用全局的Application Context来创建:
Toast.makeText(getApplicationContext(), "全局提示", Toast.LENGTH_SHORT).show();
⚠️ 注意:这种Toast默认显示在屏幕中间,而且没法用setGravity()改位置,因为它不依附任何Activity窗口。如果需要调整位置,还是用方案1。
3. 异步场景用弱引用持有Activity
如果是在网络请求、子线程回调这种异步操作里显示Toast,很容易遇到Activity已经销毁的情况。这时候用弱引用持有Activity,既能避免内存泄漏,又能检查状态:
// 在Activity里初始化弱引用 private WeakReference<Activity> mActivityRef; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mActivityRef = new WeakReference<>(this); } // 异步回调里使用 private void onAsyncTaskFinish() { Activity activity = mActivityRef.get(); if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) { Toast.makeText(activity, "异步任务完成啦", Toast.LENGTH_SHORT).show(); } }
4. 封装一个安全的Toast工具类(一劳永逸)
如果App里经常需要显示Toast,不如封装个工具类,内部自动处理Activity状态:
public class SafeToastUtil { public static void show(Activity activity, String message) { show(activity, message, Toast.LENGTH_SHORT); } public static void show(Activity activity, String message, int duration) { if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) { Toast.makeText(activity, message, duration).show(); } } } // 使用的时候直接调用就行 SafeToastUtil.show(this, "再也不会崩溃的提示");
总结
核心思路就是确保显示Toast时,对应的Activity处于活跃状态——别在Activity生命周期结束后(比如onDestroy()之后、finish()之后)调用Toast.show(),就能避免这个崩溃啦!
内容的提问来源于stack exchange,提问作者saketr64x

