android.view.WindowManager$BadTokenException修复及应用崩溃率问题咨询
问题1:android.view.WindowManager$BadTokenException 崩溃定位与修复
异常根因
从你提供的崩溃堆栈可以直接定位触发点:
android.view.WindowManager$BadTokenException: at android.view.ViewRootImpl.setView (ViewRootImpl.java:1126) at android.view.WindowManagerGlobal.addView (WindowManagerGlobal.java:439) at android.view.WindowManagerImpl.addView (WindowManagerImpl.java:95) at android.app.Dialog.show (Dialog.java:473) at androidx.appcompat.app.AlertDialog$Builder.show (AlertDialog.java:1009) at com.easyadsmm.androidapp.SplashScreen$1.onFailure (SplashScreen.java:508) at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1.lambda$onFailure$1 (DefaultCallAdapterFactory.java:96) ...
该异常的核心原因是你尝试弹窗的Activity上下文已经失效:SplashScreen启动页发起的Retrofit异步请求返回失败时,用户已经关闭了启动页(比如按返回键回到桌面、切到其他应用),此时Activity已经走了销毁流程,再用这个失效的Activity作为Context弹AlertDialog就会触发该异常。
修复方案
- 弹窗前增加Activity状态校验:调用
isFinishing()和isDestroyed()方法判断页面状态,只有两个方法都返回false时再执行弹窗逻辑,示例代码如下:
// SplashScreen.java第508行附近的onFailure回调中修改逻辑 @Override public void onFailure(Call<T> call, Throwable t) { // 先校验页面状态 if (SplashScreen.this.isFinishing() || SplashScreen.this.isDestroyed()) { return; } // 原有弹窗逻辑 new AlertDialog.Builder(SplashScreen.this) // 你的弹窗配置 .show(); }
- 页面销毁时取消未完成的网络请求:在SplashScreen的
onDestroy()生命周期方法中,对本次发起的Retrofit请求调用cancel()方法,避免页面销毁后回调继续执行。 - 兜底方案(非必要不推荐):如果该弹窗不需要绑定启动页生命周期,可以使用ApplicationContext创建弹窗,但需要额外申请悬浮窗权限,优先使用前两个方案即可覆盖绝大多数异常场景。
问题2:崩溃率水平评估
10.7%的崩溃率属于极高风险水平,行业通用的标准是:头部应用崩溃率要求低于0.1%,普通成熟应用崩溃率也会控制在1%以下。
你当前的应用上线仅2个月,用户基数较小,少量崩溃就会大幅拉高整体崩溃率,只要持续跟进修复所有上报的异常问题,后续用户量上升后崩溃率会快速回落至正常区间。
内容的提问来源于stack exchange,提问作者DB_cont
相关产品推荐
相关产品推荐

