Google Play崩溃报android.view.WindowManager$BadTokenException如何解决
错误根因
该android.view.WindowManager$BadTokenException报错的核心原因是:onReceivedError是WebView的异步回调,当回调触发时,你传入Dialog构造的facebook.this对应的Activity已经被销毁(比如用户快速返回、切后台被系统回收、deeplink跳转后立即关闭页面等场景),此时尝试依附已经不存在的Activity窗口弹出AlertDialog,系统无法找到对应的窗口令牌就会抛出该异常。
修复步骤
- 第一步:弹窗之前先校验Activity存活状态
在调用alertDialog.show()之前,先判断当前Activity是否还处于活跃状态,不活跃就直接终止后续逻辑,同时给弹窗操作加异常捕获兜底:
@Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { // 新增:校验Activity状态,已销毁则不执行后续弹窗逻辑 if (facebook.this.isFinishing() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && facebook.this.isDestroyed())) { return; } // 原有逻辑 ViewGroup viewGroup = findViewById(android.R.id.content); View dialogView = LayoutInflater.from(facebook.this).inflate(R.layout.errror_dialog, viewGroup, false); Button tryagain = dialogView.findViewById(R.id.tryagain); AlertDialog.Builder builder = new AlertDialog.Builder(facebook.this); builder.setView(dialogView); AlertDialog alertDialog = builder.create(); // 新增:捕获show时的异常,兜底避免崩溃 try { alertDialog.show(); } catch (WindowManager.BadTokenException e) { e.printStackTrace(); return; } webview.setVisibility((View.INVISIBLE)); tryagain.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 点击重试时也加状态校验,避免Activity已销毁时报错 if (facebook.this.isFinishing() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && facebook.this.isDestroyed())) { return; } webview.reload(); webview.setVisibility((View.VISIBLE)); alertDialog.dismiss(); } }); }
- 第二步:绑定WebView和Activity的生命周期,避免无效回调
在Activity的onDestroy方法中主动销毁WebView,移除回调监听,避免Activity销毁后WebView还触发onReceivedError:
@Override protected void onDestroy() { if (webview != null) { // 先从父容器移除WebView ViewParent parent = webview.getParent(); if (parent instanceof ViewGroup) { ((ViewGroup) parent).removeView(webview); } // 停止加载并清空回调 webview.stopLoading(); webview.setWebViewClient(null); webview.destroy(); webview = null; } super.onDestroy(); }
- 第三步:可选适配优化
你当前使用的4参数onReceivedError方法在API 23之后已经被废弃,建议补充实现高版本的新重载方法,保证全版本报错都能被正确处理:
@Override @TargetApi(Build.VERSION_CODES.M) public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { // 复用上面的错误处理逻辑即可 onReceivedError(view, error.getErrorCode(), error.getDescription().toString(), request.getUrl().toString()); }
内容的提问来源于stack exchange,提问作者Ahmed
相关产品推荐
相关产品推荐

