WindowManager$BadTokenException(WindowManager源码分析)

本文深入探讨了WindowManager中的addView、removeView和removeViewImmediate方法的实现原理,通过分析Android 8.0源码,解决WindowManager$BadTokenException异常问题。文章详细分析了同步和异步移除的差异,并给出了不同Android版本和targetSdkVersion下的异常表现与处理策略。
摘要由CSDN通过智能技术生成

简介:

本文主要讲解WindowManager里的addView(View view, ViewGroup.LayoutParams params),removeView(View view),removeViewImmediate(View view)三个方法的实现原理,以及通过分析系统源码,解决我们在平常开发过程中使用WindowManager遇到的各种异常崩溃问题,本文因修改项目中的WindowManager$BadTokenException类型bug而来,所以以此命名。

源码版本

功能:

通过WindowManager实现一个悬浮在屏幕最上方的悬浮View,提示用户文件上传完成,以及点击查看文件内容。

//WindowManager实例获取:
mContext.getApplicationContext().getSystemService(Context.WINDOW_SERVICE)
//添加view
mWdm.addView(mToastView, mParams);
//移除View
mWdm.removeViewImmediate(mToastView);

场景1:

在使用WindowManager时候,可能会遇到这样的异常:

View xxxxx@167788  has already been added to the window manager

看到这个异常,很多开发者立马能够想到是同一个View,在没有移除情况下,又执行了addView操作,于是,在添加之前判断该View是否已经有父容器了,有,者先移除该View:

final ViewParent parent = mToastView.getParent();
if (parent != null) {
     mWdm.removeView(mToastView);
 }

改好,心想如此简单,脸上洋溢着开心的笑容,提交,打包,热更,完事,但是没想到,线上还是会报上面的异常。
于是,翻翻WindowManager里的Api,看到还有removeViewImmediate(View view)这个方法,通过文档,了解到这个方法与removeView(View view)不同在于前者是同步,后者是异步的,于是想到可能是removeView(View view)异步导致,执行添加之前View还没有来得及移除。

疑 问 : \color{red}{疑问:}

  1. removeView实现异步的方式是什么?
  2. 同步和异步表现的差异在哪里呢?
  3. 为什么在同步和异步移除的情况,得到View的父容器都是null,为什么用removeView会报异常呢?

带着疑问继续向向看吧!

于是采用同步移除的方式,测试几波,发现ok了,这下应该没事了吧,打包,热更,吃饭,哈哈哈哈哈!

场景2:

突然第二天发现这个功能偶尔还是会出现崩溃,不同的是异常信息:

Unable to add window -- window android.view.ViewRootImpl$W@c84a531 has already been added

眉头紧锁,着了,还是报什么View已经添加了,难道同步移除也不行,但是报的是ViewRootImpl已经添加了啊,这下完了,到底完没完,继续下看。

###补充:
也许发现,在不同的Android版本,手机,targetSdkVersion值,也会有不一样的现象,比如在targetSdkVersion指定在Android O及以上,当WindowManager.LayoutParams指定的类型为WindowManager.LayoutParams.TYPE_TOAST(官方已建议弃用),会直接崩溃,报以下错误:

Unable to add window -- token  null is not valid; is your activity running?

而在O以下却不会呢,这是为什么呢?带着疑问一起向下看吧!

开 饭 了 — 下 面 由 我 来 进 行 逐 一 解 疑 : \color{red}{开饭了—下面由我来进行逐一解疑:}

removeView,removeViewImmediate异同

  • WindowManager.java实现类WindowManagerImpl.java

1.分解操作:

mContext.getApplicationContext().getSystemService(Context.WINDOW_SERVICE)

//android.app.ContextImpl
@Override
public String getSystemServiceName(Class<?> serviceClass) {
    return SystemServiceRegistry.getSystemServiceName(serviceClass);
}

//android.app.SystemServiceRegistry
static{
    ...
    registerService(Context.WINDOW_SERVICE, WindowM
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值