Advertisement
Guest User

Untitled

a guest
Jun 24th, 2019
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.14 KB | None | 0 0
  1. Android应用开发之Android7.1.1出现Toast崩溃问题的解决方案
  2. 凌雪2018-09-12来源 :网络阅读 212评论 0
  3. 摘要:本文将带你了解Android应用开发之Android7.1.1出现Toast崩溃问题的解决方案,希望本文对大家学Android有所帮助。
  4.  
  5. 本文将带你了解Android应用开发之Android7.1.1出现Toast崩溃问题的解决方案,希望本文对大家学Android有所帮助。
  6.  
  7.  
  8.  
  9. 概述
  10. Toast作为Android应用中最常见的一种提示方式,由于简单的api设计和简洁的交互体验被我们广泛使用,但是这并代表他很完美,本文将记录我在开发中遇到的问题。
  11. 背景
  12. 最近项目好多用户反应有bug,然后看log出现了一个奇怪的问题,而且次数不很多,如下:
  13. #1664 android.view.WindowManager$BadTokenExceptionUnable to add window -- window android.view.ViewRootImpl$W@4a51004 has already been addedandroid.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)
  14. 然后发现居然都是7.1.1设备才出现的,见下图:
  15.  
  16. Toast显示与隐藏
  17. 首先Toast显示依赖于一个窗口,这个窗口被WMS管理(WindowManagerService),当需要show的时候这个请求会放在WMS请求队列中,并且会传递一个TN类型的Bider对象给WMS,WMS并生成一个token传递给Android进行显示与隐藏,但是如果UI线程的某个线程发生了阻塞,并且已经NotificationManager检测已经超时就不删除token记录,此时token已经过期,阻塞结束的时候再显示的时候就发生了异常。
  18. 在android7.1.1的Toast源码handleShow是这样写的:
  19. ?1mWM.addView(mView, mParams);
  20. 而在8.0则是这样的:
  21. ?123456try { mWM.addView(mView, mParams); trySendAccessibilityEvent(); } catch (WindowManager.BadTokenException e) { /* ignore */ }
  22. 到这里能看到在发生异常的时候使用了try catch捕获,程序不会挂掉
  23. 解决方案
  24. /** * @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执行 } }}
  25.  
  26. 本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之Android频道!
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement