当前位置: 移动技术网 > IT编程>移动开发>Android > Android7.1.1出现Toast崩溃问题的解决方案

Android7.1.1出现Toast崩溃问题的解决方案

2018年09月29日  | 移动技术网IT编程  | 我要评论

收藏古玩网,我猛然进入儿媳的身体,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执行
     }
   }
}

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网