android toast window,Android7.1 Toast崩溃解决方案 android.view.WindowManager$BadTokenException

今日无事,翻看Bugly的错误日志,想着解决几个线上BUG充当这周的周报内容,发现了一个很怪的BUG:

android.view.WindowManager$BadTokenException

Unable to add window -- token android.os.BinderProxy@184bc7e is not valid; is your activity running?

46e8fe034350

46e8fe034350

而且大部分集中在Android7.1的系统,是不是很调皮?搜索了一下,也终于是找到了参考,由于我本人和现有机型均无法复现,所以只能参考网上的资料加以修改,等下次版本更新再看情况,此次记录也是给自己做个记忆,方便日后参考!

Toast显示与隐藏

首先Toast显示依赖于一个窗口,这个窗口被WMS管理(WindowManagerService),当需要show的时候这个请求会放在WMS请求队列中,并且会传递一个TN类型的Bider对象给WMS,WMS并生成一个token传递给Android进行显示与隐藏,但是如果UI线程的某个线程发生了阻塞,并且已经NotificationManager检测已经超时就不删除token记录,此时token已经过期,阻塞结束的时候再显示的时候就发生了异常。

在android7.1.1的Toast源码handleShow是这样写的:

mWM.addView(mView, mParams);

而在8.0则是这样的:

try {

mWM.addView(mView, mParams);

trySendAccessibilityEvent();

} catch (WindowManager.BadTokenException e) {

/* ignore */

}

到这里能看到在发生异常的时候使用了try catch捕获,程序不会挂掉

解决方案:

/**

* @author CH

* @date 2018/6/26

* 部分7.1.1手机崩溃Toast解决方案

*/

public class ToastCompat {

private static Field sField_TN;

private static Field sField_TN_Handler;

private Toast mToast;

static {

try {

sField_TN = Toast.class.getDeclaredField("mTN");

sField_TN.setAccessible(true);

sField_TN_Handler = sField_TN.getType().getDeclaredField("mHandler");

sField_TN_Handler.setAccessible(true);

} catch (Exception e) {

}

}

private static void hook(Toast toast) {

try {

Object tn = sField_TN.get(toast);

Handler preHandler = (Handler) sField_TN_Handler.get(tn);

sField_TN_Handler.set(tn, new SafelyHandlerWarpper(preHandler));

} catch (Exception e) {

}

}

public void showToast(Context context, CharSequence cs, int length) {

if (mToast == null) {

mToast = Toast.makeText(context, cs, length);

} else {

mToast.setText(cs);

}

hook(mToast);

mToast.show();

}

public static class SafelyHandlerWarpper extends Handler {

private Handler impl;

public SafelyHandlerWarpper(Handler impl) {

this.impl = impl;

}

@Override

public void dispatchMessage(Message msg) {

try {

super.dispatchMessage(msg);

} catch (Exception e) {

}

}

@Override

public void handleMessage(Message msg) {

impl.handleMessage(msg);//需要委托给原Handler执行

}

}

}

简单来说就是通过反射注入在发生异常的地方进行try catch

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值