美文网首页
Toast 引起的android.view.WindowMana

Toast 引起的android.view.WindowMana

作者: skyboyhp | 来源:发表于2019-07-22 14:47 被阅读0次

    最近通过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

    相关文章

      网友评论

          本文标题:Toast 引起的android.view.WindowMana

          本文链接:https://www.haomeiwen.com/subject/kuailctx.html