概述:需要了解基本流程,作为应用层开发不用纠结细节;wms真正管理的decor view; 对view的 update,remove,add
(1)Framework层的窗口管理服务
职责是管理Android系统中的所有的Window。窗口管理服务,继承IWindowManagerStub,Binder服务端,因此WM与WMS的交互也是一个IPC的过程
(1)mWindow
PhoneWindow对象,继承于Window,是窗口对象
(2)mWindowManager
WindowManagerImpl对象,实现WindowManager接口
(3)mMainThread
Activity对象,并非真正的线程,是运行在主线程里的对象
(4)mUIThread
Thread对象,主线程
(5)mHandler
Handler对象,主线程Handler
(6)mDecor
View对象,用来显示Activity里的视图
(1)SystemServerstartOtherServices
(3)总结
(1)应用窗口 (Application Window)
包括所有应用程序自己创建的窗口,以及在应用起来之前系统负责显示的窗口,层级范围是1~99
(2)子窗口(Sub Window)
应用自定义的对话框,或者输入法窗口,子窗口必须依附于某个应用窗口(设置相同的token),层级范围是1000~1999
下面是具体源码部分,了解了下,没具体看,等要做room开发的时候再细看,应用开发了解大概原理即可--------
最近接了一个语音控制的功能,UI上的具体实现就是在应用上遮盖一个透明防触层,在语音状态下阻止用户点击,但不能影响物理返回键的Dialog呼出即控制,同时对于非物理返回键呼出的Dialog也要阻止 *** 作。功能看起来很绕,我们用一张来具体说明一下。
通过不难看出,我们要实现的语音控制层其实是介于应用视图与视图内部提示框之上,同时又在Back返回键d窗之下的一个层级。因为一直以来对安卓视图层级的探究不是很深入,所以借着做这个功能对安卓视图层级这一块的知识进行了一下总结梳理。
首先让我们通过一张层级图来明确几个重要的概念Window,DecorView和mContentParent。
在Android中不管是Activity、Toast、ActionBar还是Dialog,他们的视图都是附加到Window上,其实基本上所有的view同时通过Window来呈现的,因此Window可以理解为是view的承载者和管理者。Window 有三种类型,分别是应用 Window、子 Window 和系统 Window。应用类 Window 对应一个 Acitivity,子 Window 不能单独存在,需要依附在特定的父 Window 中,比如常见的一些 Dialog 就是一个子 Window。系统 Window是需要声明权限才能创建的 Window,比如 Toast 和系统状态栏都是系统 Window。
DecorView是Windows中的View的最顶层View。其实DecorView是FrameLayout的子类,它里面包含了一个存有ActionBar以及mContentParent的LinearLayout。
mContentParent这个名字可能会有些陌生,其实他就是我们经常使用的应用根布局,即androidRidcontent。Activity中的setContentView其实就是通过LayoutInflater将XML布局转换成View并添加到mContentParent中。
每个Activity都会持有一个Window,而在安卓中,Window只有唯一的一个实现类PhoneWindow ,所以每个Activity都会持有一个PhoneWindow,在PhoneWindow中会持有顶层视图DecorView。那么Activity是怎么建立与PhoneWindow的联系的呢,让我们通过源码来探究一下:
在Activity的启动过程中会执行ActivityThread的performLaunchActivity方法,其中调用Activity的attach。在attach()方法中实例化Activity持有的mWindow。由于 Activity 实现了 Window 的 Callback 接口,因此当 Window 接受到外界的状态改变时就会回调 Activity 的方法。
可以看到,在PhoneWindow里面,出现了成员变量DecorView。而这里,DecorView则是PhoneWindow里面的一个内部类,它是继承于FrameLayout。
这是我们每次写Activity都会调用的setContentView方法,它的内部调用了getWindow()的setContentView,这个mWindow就是PhoneWindow。
我们看到在PhoneWindow中有三个setContentView的重载方法。在setContentView(int layoutResID)中,首先判断了mContentParent ,如果mContentParent 为空即为第一次调用的时候,就执行installDecor()方法,创建DecorView,并添加到mContentParent上。如果mContentParent不为空,那么将mContentParent中的view移除。接着通过mLayoutInflater将XML转换为View树,并且添加至mContentParent视图中。 添加完成后回调通知onContentChanged,表示完成界面加载。
首先判断mDecor是否为空,如果为空则通过generateDecor创建一个DecorView,紧接着设置DecorView的获取焦点能力为FOCUS_AFTER_DESCENDANTS,即先分发给Child View进行处理,如果所有的Child View都没有处理,则自己再处理。第一次DecorView未加载到mContentParent,所以mContentParent为空,调用generateLayout将setContentView内容添加到mContentParent。
定制过Acitivity的Actionbar或是Fullscreen的同学一定都知道,requesetFeature方法需要在setContentView之前调用,这就是原因。setContentView的实质显示是触发了Activity的resume状态,也就是触发了makeVisible方法。
这里将getWindow()getAttributes()作为了LayoutParams,在WindowManager中:
可以看到Activity的窗口类型是TYPE_APPLICATION,这个TYPE类型决定了在Window层的显示层级,TYPE类型总览如下:
Dialog不属于View,他是应用的子window,所以这也是为什么我们通过给mContentParent添加view无法实现遮挡Dialog的原因。Dialog 中 Window 同样是通过 PolicyManager 的 makeNewWindow 方法来完成的,普通的 Dialog 必须采用 Activity 的 Context,如果采用 Application 的 Context 就会报错。这是因为没有应用 token 导致的,而应用 token 一般只有 Activity 拥有。常规Dialog的TYPE为TYPE_APPLICATION_ATTACHED_DIALOG,通过不同的TYPE层级划分我们可以找到置于常规Dialog之上的WindowManager LayoutParams 属性,例如TYPE_SYSTEM_ALERT与TYPE_TOAST,设置了这两个属性的布局是可以将常规Dialog完全遮盖的。他们的区别在于一个是系统级别的Dialog一个是Toast,系统Dialog需要申请权限。所以我们的第一个方案就是可遮挡的Dialog使用常规Dialog,语音提示框采用TYPE_SYSTEM_ALERT。但是都知道安卓有一个无法逃避的问题,就是厂商定制,在MUI的framework层,出于对“安全”的考虑,默认为用户关闭了悬浮窗权限,也就是是说设置了TYPE_SYSTEM_ALERT属性的视图默认是无法显示的,需要用户手动开启权限以后方可显示。
虽然可以在用户启动的时候根据用户机型选择跳转开启权限页,但作为一个有情怀的开发这种不完美的体验还是不能接受的。根据之前对安卓视图层级的学习,我们有了第二套方案。应用视图是存放于mContentParent他与Activity同属TYPE_APPLICATION Window层级属于最下层,常规Dialog的层级是TYPE_APPLICATION_ATTACHED_DIALOG,所以我们将常规Dialog作为最上层不可遮挡的提示框,下面只需考虑可遮挡的d窗与语音控制两层即可。因为语音控制层需要能够遮挡提示d窗,所以需要语音控制层在d窗的上层,经过之前的学习,我们把d窗加入到mContentParent,把语音控制层添加到DecorView层即可完美的解决问题。mContentParent为一个FrameLayout,应用视图通过sentContentView率先添加到mContentParent中,作为提示d窗,添加顺序一定相对应用视图置后,所以当提示d窗再次向mContentParent添加的时候,即会添加到应用视图之上。而DecorView是mContentParent的父容器,也是一个FrameLayout,添加语音提示框的时候mContentParent一定已经存在,所以添加的时候一定会在mContentParent之上。
就这样,一个看似复杂的需求通过对安卓源码的探究完美的解决了,很多时候当我们遇到难以解决的问题,不妨试试回到问题的原点,思考一下问题的本质,很多时候都会有不一样的发现。
以上就是关于androidframework13-14-wms全部的内容,包括:androidframework13-14-wms、安卓视图层级大揭秘、等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)