Toast 引起的android.view.WindowMana

2019-07-22  本文已影响0人  skyboyhp

最近通过bugly日志观察到,
android.view.WindowManager$BadTokenException
Unable to add window -- token android.os.BinderProxy@5ce16c1 is not valid; is your activity running?

出现了Android 7.1.1跟7.1.2的手机系统上。

android.view.ViewRootImpl.setView(ViewRootImpl.java:688)
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:181)
android.app.ActivityThread.main(ActivityThread.java:6294)
java.lang.reflect.Method.invoke(Native Method)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:793)

根据上面的日志信息,我们可以 看到 是Toast 内的handleShow方法调用了addView造成的。
查看原码比对。
handleShow()方法中 Android 26之前

if (mView.getParent() != null) {
      if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
      mWM.removeView(mView);
}
if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
mWM.addView(mView, mParams);
trySendAccessibilityEvent();

Android 26版本开始

if (mView.getParent() != null) {
      if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
      mWM.removeView(mView);
}
if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
// Since the notification manager service cancels the token right
 // after it notifies us to cancel the toast there is an inherent
// race and we may attempt to add a window after the token has been
// invalidated. Let us hedge against that.
try {
      mWM.addView(mView, mParams);
      trySendAccessibilityEvent();
      } catch (WindowManager.BadTokenException e) {
       /* ignore */
      }

这里可能会有另一个疑问了,我try{}catch为什么也不生效。
This exception occurs regardless of whether the Context you passed to Toast is an Activity or ApplicationContext or Service. And you can not try-catch it.

Toast.show 函数外增加 try-catch 是没有意义的。因为 Toast.show 实际上只是发了一条命令给 NotificationManager 服务。真正的显示需要等 NotificationManager 通知我们的 TN 对象 show 的时候才能触发。NotificationManager 通知给 TN 对象的消息,都会被 TN.mHandler 这个内部对象进行处理

如何解决呢?

关于问题的详细解析,找到腾讯 QQ音乐团队的播客:
这也是我在APP中采用 技术方案。
https://www.cnblogs.com/qcloud1001/p/8421356.html
https://cloud.tencent.com/developer/article/1034223

在github上找到解决的,但感觉不太完美,有限制,对代码改动较大。
https://github.com/PureWriter/ToastCompat
https://github.com/cat9/ToastCompat

上一篇下一篇

猜你喜欢

热点阅读