Android7.1.1出现Toast崩溃问题的解决方案
程序员文章站
2022-05-01 17:52:00
概述
toast作为android应用中最常见的一种提示方式,由于简单的api设计和简洁的交互体验被我们广泛使用,但是这并代表他很完美,本文将记录我在开发中遇到的问题。
背景
最近项目好多用户反应有...
概述
toast作为android应用中最常见的一种提示方式,由于简单的api设计和简洁的交互体验被我们广泛使用,但是这并代表他很完美,本文将记录我在开发中遇到的问题。
背景
最近项目好多用户反应有bug,然后看log出现了一个奇怪的问题,而且次数不很多,如下:
#1664 android.view.windowmanager$badtokenexception unable to add window -- window android.view.viewrootimpl$w@4a51004 has already been added android.view.viewrootimpl.setview(viewrootimpl.java:695) android.view.viewrootimpl.setview(viewrootimpl.java:691) android.view.windowmanagerglobal.addview(windowmanagerglobal.java:342) android.view.windowmanagerimpl.addview(windowmanagerimpl.java:94) android.widget.toast$tn.handleshow(toast.java:506) android.widget.toast$tn$2.handlemessage(toast.java:389) android.os.handler.dispatchmessage(handler.java:102) android.os.looper.loop(looper.java:154) android.app.activitythread.main(activitythread.java:6292) java.lang.reflect.method.invoke(native method) com.android.internal.os.zygoteinit$methodandargscaller.run(zygoteinit.java:906) com.android.internal.os.zygoteinit.main(zygoteinit.java:796)
然后发现居然都是7.1.1设备才出现的,见下图:
toast显示与隐藏
首先toast显示依赖于一个窗口,这个窗口被wms管理(windowmanagerservice),当需要show的时候这个请求会放在wms请求队列中,并且会传递一个tn类型的bider对象给wms,wms并生成一个token传递给android进行显示与隐藏,但是如果ui线程的某个线程发生了阻塞,并且已经notificationmanager检测已经超时就不删除token记录,此时token已经过期,阻塞结束的时候再显示的时候就发生了异常。
在android7.1.1的toasthandleshow是这样写的:
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执行 } } }
推荐阅读
-
IE浏览器登录网上银行时出现崩溃问题的解决办法
-
AndroidStudio中AVD虚拟机设备空间不足调试过程出现的黑屏问题及解决方案
-
Excel导入数据库时出现的文本截断问题解决方案
-
.net下灰度模式图像在创建Graphics时出现:无法从带有索引像素格式的图像创建graphics对象 问题的解决方案。
-
Oracle导dmp出现文件ORA-12154: TNS: 无法解析指定的连接标识符问题的解决方案
-
Vue项目部署在Spring Boot出现页面空白问题的解决方案
-
python中通过pip安装库文件时出现“EnvironmentError: [WinError 5] 拒绝访问”的问题及解决方案
-
win10安装ubuntu系统出现的一些问题以及解决方案
-
Android7.1.1出现Toast崩溃问题的解决方案
-
IE浏览器登录网上银行时出现崩溃问题的解决办法