收藏古玩网,我猛然进入儿媳的身体,2tu迅播影院
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执行 } } }
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
Android apk 项目一键打包并上传到蒲公英的实现方法
Android 自定义LineLayout实现满屏任意拖动功能的示例代码
android 限制某个操作每天只能操作指定的次数(示例代码详解)
Android 集成 google 登录并获取性别等隐私信息的实现代码
网友评论