简介
上一篇分析了WindowManager$BadTokenException发生的原因,带大家一起通过分析WindowManager源码,更加深入的了解了WindowManager添加window的过程,以及在使用WindowManager添加自己的window或者View的时候,怎么去避免发生异常,接下来,继续深入分析WindowManager源码,带大家一起寻找,解决平时使用WindowManager出现的各种异常的办法。
建 议 : \color{blue}{建议:} 建议:本文章讲解,建立在上一篇文章的基础之上,所以阅读本文章前,请先阅读上一篇文章,地址如下:
WindowManager$BadTokenException(WindowManager源码分析
###源码版本
在没有特别说明的情况下,源码版本如下:
-
sdk:android-28
-
Android系统源码:Android8.0
###window类型
Window有三种类型,分别是应用Window,子Window和系统Window。 -
应用类Window对应着一个Activity。
-
子Window不能单独存在,它需要附属在特定的父Window中,比如Dialog就是一个子Window。
-
系统Window是需要声明权限才能创建的Window,比如Toast和系统状态栏这些都是系统Window。
Window是分层的,每个Window都有对应的z-ordered,层级大的会覆盖 在层级小的Window上。在三类 Window中,应用Window的层级范围是1~99,子Window的层级范围是1000~1999,系统Window的层级范 围是2000~2999。很显然系统Window的层级是最大的,而且系统层级有很多值,一般我们可以选用 TYPE_SYSTEM_ERROR或者TYPE_SYSTEM_OVERLAY,另外重要的是要记得在清单文件中声明权限。
系统Window
由于源码比较多,只讲解关键或者不容易判断的代码,其它可以自行查看。
- 函数 :addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow)
源码文件:WindowManagerGlobal.java
- root = new ViewRootImpl(view.getContext(), display);
创建ViewRootImpl,看一下里面创建的几个关键的对象
(1) mWindow = new W(this);
(2) mWindowSession = WindowManagerGlobal.getWindowSession();
- 函数:setView(View view, WindowManager.LayoutParams attrs, View panelParentView)
源码文件:ViewRootImpl.java
- 参数变化:
(1) attrsmWindowAttributes.copyFrom(attrs); if (mWindowAttributes.packageName == null) { mWindowAttributes.packageName = mBasePackageName; } attrs = mWindowAttributes;
- 函数:addWindow(Session session, IWindow client, int seq,WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets,InputChannel outInputChannel)
-
参数
(1)session: mWindowSession
(2)client:mWindow
(3)attrs:mWindowAttributes包含了传入时WindowManager.LayoutParams参数的所有属性 -
权限检测: int res = mPolicy.checkAddPermission(attrs, appOp)
函数:checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp)
源码路径:frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
(1)如果不在window类型里,返回无效类型 —— ADD_INVALID_TYPEif (!((type >= FIRST_APPLICATION_WINDOW && type <