当前位置: 首页 > news >正文

Android7.1.1系统,Toast的Exception: android.view.WindowManager$BadTokenException解决

 7.1.1系统版本,我发现问题很多,比如 有个接口字段用了base64,但是我添加包的时候用的 java.util.base64 结果会崩溃报错,网上搜索后要用 android.util.base64 来解决,

 今天发现突然有崩溃,看了下崩溃信息

 

Fatal Exception: android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@fcd9ef6 is not valid; is your activity running?
       at android.view.ViewRootImpl.setView(ViewRootImpl.java:806)
       at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:369)
       at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:94)
       at android.widget.Toast$TN.handleShow(Toast.java:459)
       at android.widget.Toast$TN$2.handleMessage(Toast.java:342)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:186)
       at android.app.ActivityThread.main(ActivityThread.java:6491)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:914)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:804)

一下解决办法是我网上转过来的,经过自测后,解决了我的问题,我这边记录

这个BadTokenException是由谷歌系统产生的BUG,只有在系统7.x会产生,谷歌团队已经在8.0以上系统修复,但对于开发者来说面对android的7.x系统的用户不得不去解决这个BUG

BadTokenException产生的原因及谷歌的解决方案
在Toast.show()之后,UI线程做了耗时的操作阻塞了Handlermessage的处理。7.X系统对TYPE_TOAST的Window类型做了超时限制,绑定了WindowToken,如果UI在这段时间内没有执行完,Toast.show()内部的handlermessage得不到执行,NotificationManageService那端会把这个Toast取消掉,同时把Toast对于的windowtoken置为无效。等App端真正需要显示Toast时,因为windowtoken已经失效,ViewRootImpl就抛出了上面的异常。

我们看一下谷歌源码是如何解决的,8.0以上系统Toast的handleShow 方法里面的一段代码,mWM.addView(mView, mParams),是被try catch 了,在7.x的系统是没有被catch住的(这里就不贴代码了)
 

看到谷歌的解决方案,所以我们7.x的解决方案其实也是把异常给catch 住。那如何catch住呢?我们看Toast的源码时里面有个mHandler的成员变量,我们想办法把分发消息的dispatchMessage(Message msg) 异常捕获不就可以了吗?这个其实和谷歌的解决方案一样。

 这里我们采用Java的反射机制
 

try {
      sField_TN = Toast.class.getDeclaredField("mTN");
      sField_TN.setAccessible(true);
      sField_TN_Handler = sField_TN.getType().getDeclaredField("mHandler");
      sField_TN_Handler.setAccessible(true);
      Object tn = sField_TN.get(toast);
      //获取原有的Handler
      Handler preHandler = (Handler) sField_TN_Handler.get(tn);
      //设置自定义的Handler
      sField_TN_Handler.set(tn, new SafelyHandlerWarpper(preHandler));
    } catch (Exception e) {
    }

  这里我们设置自定义的Handler

/****
     * 自定义Handler catch处理异常
     */
    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执行
        }
    }
 

我们把dispatchMessage给catch住,handleMessage处理的消息具体实现还是原有的handler处理逻辑,不去影响原有的处理逻辑,我们只是catch住异常防止应用崩溃。

完整实现类如下:

/***
 * create by wuchu
 * 解决部分7.1.1手机崩溃Toast解决方案
 */
public class ZtAppCompatToast {
 
    private static Field sField_TN;
    private static Field sField_TN_Handler;
 
    private Toast mToast;
 
 
    static {
        //安卓7.0的做处理,其它版本系统的不用处理
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1 && Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
            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) {
            }
        }
    }
 
    public ZtAppCompatToast(Context context) {
        mToast = new Toast(context);
        setHook(mToast);
    }
 
    public Toast getToast() {
        return mToast;
    }
 
    public static Toast makeText(Context context,
                                 CharSequence text, int duration) {
        Toast toast = Toast.makeText(context, text, duration);
        setHook(toast);
        return toast;
    }
 
    public static Toast makeText(Context context,
                                 int textSrc, int duration) {
        Toast toast = Toast.makeText(context, textSrc, duration);
        setHook(toast);
        return toast;
    }
 
    private static void setHook(Toast toast) {
        //安卓7.0的做处理,其它版本系统的不用处理
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1 && Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
            hook(toast);
        }
    }
 
    /*****
     *
     * @param toast
     */
    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) {
        }
    }
 
    /****
     * 自定义Handler catch处理异常
     */
    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执行
        }
    }
 
}

相关文章:

  • TiKV 监控指标详解
  • 嵌入式系统开发笔记92:感受开源之美
  • VLC 编译安装 [for android, linux, windows]
  • 字节内部私藏的数据结构与算法刷题笔记,太顶了熬夜刷上头
  • 前端性能优化方法与实战开篇词 开启刻意练习之路,进阶前端性能技术专家
  • 实战java高并发程序设计(第2版)学习(1-3)
  • TiCDC 重要监控指标详解
  • T1063 最大跨度值(信息学一本通C++)
  • JavaSE 一些技巧 03——Stream流常用API
  • VMware安装Android-x86示例
  • [HUBUCTF 2022 新生赛]
  • 【Machine Learning】13.逻辑回归小结and练习
  • Cadence Allegro 过孔通孔盲孔埋孔详细说明及设计举例图文教程
  • Spring boot再来一遍
  • Mathorcup数学建模竞赛第三届-【妈妈杯】B题:关于三维健康评分模型的研究(附带赛题解析获奖论文)(一)
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • ABAP的include关键字,Java的import, C的include和C4C ABSL 的import比较
  • Angular4 模板式表单用法以及验证
  • leetcode46 Permutation 排列组合
  • PHP那些事儿
  • Puppeteer:浏览器控制器
  • RedisSerializer之JdkSerializationRedisSerializer分析
  • spring boot 整合mybatis 无法输出sql的问题
  • Transformer-XL: Unleashing the Potential of Attention Models
  • 不发不行!Netty集成文字图片聊天室外加TCP/IP软硬件通信
  • 技术发展面试
  • 聊聊springcloud的EurekaClientAutoConfiguration
  • 前嗅ForeSpider教程:创建模板
  • 怎么将电脑中的声音录制成WAV格式
  • 正则学习笔记
  • PostgreSQL之连接数修改
  • ​Linux Ubuntu环境下使用docker构建spark运行环境(超级详细)
  • ​草莓熊python turtle绘图代码(玫瑰花版)附源代码
  • !$boo在php中什么意思,php前戏
  • # linux 中使用 visudo 命令,怎么保存退出?
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • #《AI中文版》V3 第 1 章 概述
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • (java版)排序算法----【冒泡,选择,插入,希尔,快速排序,归并排序,基数排序】超详细~~
  • (分类)KNN算法- 参数调优
  • (六)c52学习之旅-独立按键
  • (六)vue-router+UI组件库
  • (七)Java对象在Hibernate持久化层的状态
  • (三十五)大数据实战——Superset可视化平台搭建
  • (转)Linux NTP配置详解 (Network Time Protocol)
  • (转载)PyTorch代码规范最佳实践和样式指南
  • (最优化理论与方法)第二章最优化所需基础知识-第三节:重要凸集举例
  • **python多态
  • .naturalWidth 和naturalHeight属性,
  • .Net Attribute详解(上)-Attribute本质以及一个简单示例
  • .net core MVC 通过 Filters 过滤器拦截请求及响应内容
  • .NET HttpWebRequest、WebClient、HttpClient
  • .NET 除了用 Task 之外,如何自己写一个可以 await 的对象?
  • .NET/C# 将一个命令行参数字符串转换为命令行参数数组 args
  • .Net7 环境安装配置