源码阅读--窗口View系统

结构

这里写图片描述

应用端

应用端主要负责输入事件的分发处理,view的绘制等,activity在这里扮演的是一个比较弱的角色,一个顶层的分发者,Activity、Dialog等Window承载者实现了Window.Callback接口,定义了一系列dispatchXXXEvent方法。
Activity持有mWindow和mWindowManager两个成员,mWindow是PhoneWindow类对象,对应着看到的一个窗口,PhoneWindow的成员mDeorView成员是整个Window的根布局,跟各种ViewGroup和View实现类构成整个页面结构;mWindowManager是WindowManagerImpl类的实例,主要负责View相关管理工作,通过WindowManagerGlobal管理对应的窗口,WindowManagerGlobal以View的形式管理应用端所有的窗口,三个成员mViews 、mRoots、mParams分别保存根View,RootViewImpl,WindowManager.LayoutParams对象,三者一一对应,根View包括了整个页面View结构,ViewRootImpl负责应用端与WMS的交互、事件分发处理以及View绘制处理,WindowManager.LayoutParams则存储了Window相关属性,用于WMS的窗口管理。
ViewRootImpl是应用端的核心,通过IWindow与服务端交互进行窗口相关管理;通过WindowInputEventReceiver接受输入事件并进行分发;通过Choreographer接受VSYNC信号进行动画、绘制同步控制。

事件分发流程

这里写图片描述

上图展示了应用端收到InputEvent到分发到View层级结构之前的分发流层,其中ViewRootImpl在添加window的时候在setView方法中会创建InputStage责任链,上图中在ViewPostImeInputStage节点会分类处理InputEvent。

        @Override
        protected int onProcess(QueuedInputEvent q) {
            if (q.mEvent instanceof KeyEvent) {
                return processKeyEvent(q);
            } else {
                final int source = q.mEvent.getSource();
                if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
                    return processPointerEvent(q);
                } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
                    return processTrackballEvent(q);
                } else {
                    return processGenericMotionEvent(q);
                }
            }
        }

DecorView重写了View的dispatchTouchEvent方法,绕道Activity(Window.Callback)调用了dispatchTouchEvent方法,使得Activity可以处理Touch事件。然后通过PhoneWindow再次分发回DecorView,到View层级结构。下面就是比较熟悉的Touch事件在View层级结构的分发流程。

View层级结构Touch事件分发
Activity启动时Window添加流程

这里写图片描述

PhoneWindow对象在Activity调用attach方法时创建,在setContentView调用时创建DecorView对象,setContentView方法设置了内容区域的对应布局,最终会通过LayoutInflator加载到DecorView的对应子布局,在此之前generateLayout方法会根据窗口属性等对DecorView进行一系列的初始化操作。
在activity的Resume阶段,会通过windowmanagerImpl的addView方法通过ViewRootImpl把对应窗口添加到WMS。

服务端

窗口类型

窗口分为三类
1.应用窗口(Application Window)
应用窗口对应着一个Activity,也就是Activity对应的主窗口,最常见的一级窗口,窗口Token对应Activity的Token
2.子窗口(SubWindow)
与一级窗口关联,依附于一级窗口的窗口,Token对应关联的主窗口的token,同一主窗口的子窗口的Token相同,通过该token可以获取主窗体下的所有子窗体,WMS中有对应操作。
3.系统窗口(System Window)
系统窗口一般不用于应用如输入法窗口、toast、状态栏等;可以使用系统窗口实现浮窗效果,使用时需要声明权限

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> 
相关类与数据结构

在WindowManagerService中主要有三个用于窗口管理的成员mWindowMap,mTokenMap和mDisplayContents.
mWindowMap HashMap 保存了所有的WindowState实例,键值是应用端IWindow对象对应的IBinder,每一个Entry对应着一个窗口
mTokenMap HashMap 保存了窗口对应的token,键值是一个Token值,该键值对应窗口LayoutParams的token属性;这里的窗口Token对应的是顶级窗口的Token,与窗口不是一对一的关系;子窗口共享主窗口的Token,在WindowToken中有mWindows对象,这是一个WindowList类的实例,保存了该token下的所有窗口。
mDisplayContents SparseArray 保存了所有的DisplayContent,默认大小是2;DisplayContent中的mWindows同样是WindowList类的实例,以Z-order保存了所有的WindowState窗口对象,序号越大表示窗口越靠上。窗口的展示就是根据mWindows的排序结果进行的,WMS对窗口的Z-order管理也是对该列表进行操作。
WindowState

窗口Z-order管理

平面和垂直于平面的直线可以构成三维空间坐标,以手机屏幕所在的平面为准,垂直于手机平面方向可以构成一个三维空间坐标,按照坐标系的习惯垂直方向定义为Z轴,如果我们把每个窗口具象化成有厚度的纸片,按照DisplayContent管理窗口的顺序把这些纸片叠起来,纸片的叠加顺序也就对应了窗口的Z-order。

WMS添加窗口

WMS通过addWindow添加对应的窗口信息,应用端和WMS通过IWindow和IWindowSession一对Binder对象进行进程间交互,ViewRootImpl的内部类W实现了IWindow,服务端对应的Session实现了IWindowSession。上图中应用端调用addView方法最终会导致WMS中addWindow方法被调用。
addWindow完成了以下工作
1.根据应用端的参数信息(WindowManager.LayoutParams等)校验窗口是否合法
2.创建WindowState对象,添加到mWindowMap
3.按正确的顺序添加窗口到DisplayContent的mWindows

窗口添加校验

需要校验对应DisplayContent是否可用、是否重复添加、如果是子窗口需要验证主窗口是否存在,关联主窗口不能是子窗口类型,如下
这里写图片描述
根据WindowManager.LayoutParams的Token获取窗口Token(mTokenMap),这里按照逻辑推测,在添加Window之前应用窗口和一些系统窗口的Token已添加到mTokenMap中,否则添加失败;应用窗口还要求Token有对应的AppWindowToken;系统窗口Token中的窗口类型标识要与带添加窗口类型一致。代码太长,不贴了。

创建WindowState

上面一系列检查完成后,就会创建WindowState对象

确定窗口Z-order,添加窗口

这里写图片描述
非输入法窗口会调用方法addWindowToListInOrderLocked
这里写图片描述

根据窗口类型又会分别调用不同方法
以应用窗口分析addAppWindowToListLocked正式进入Z-order管理
这里写图片描述
getTokenWindowsOnDisplay()方法会遍历Token下的窗口列表筛选出在指定DisplayContent上显示的Windows,如果结果不为空说明已有Token相关的窗口添加过,添加窗口过程只需要把窗口添加到Token对应窗口在DisplayContent窗口列表中的区域。

这里写图片描述

上图注释很清楚,除了TYPE_BASE_APPLICATION和StartingWindow之外,直接把要添加的窗口添加到token对应的所有窗口的上面。
借老罗博客上的一张图,直观的表明了窗口的Z轴分布

这里写图片描述

继续addAppWindowToListLocked,如果根据Token筛选出的窗口列表是空的,说明还没有添加过相关应用窗口,这时候就要根据Activity栈来判断应该把窗口放置到什么位置。
后向遍历Activity栈找到与要添加窗口对应的AppWindowToken,记录上一个Token对应的最下层窗口位置,添加新窗口到该位置之前。
如果没有找到对应位置继续遍历,找到第一个有窗口对应的Token,添加到其底层窗口之前

问题

补个流程图
添加应用窗口是,mTokenMap已经保存了对应Token,什么时候保存的?
Token关系整理
DispalyContent TaskStack 与Task

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Framework 层是 Android 系统中非常重要的一层,它提供了丰富的 API 和服务,包括 Activity、Service、Content Provider、Broadcast Receiver、PackageManager、Window Manager 等等,它们为应用程序提供了一个丰富的运行环境和开发框架。 Android Framework 层的源码主要包括以下几个部分: 1. Activity Manager:负责管理 Android 应用程序的生命周期、进程和任务栈等。 2. Package Manager:负责管理应用程序的安装、卸载和更新等操作。 3. Content Provider:提供了一种标准的接口,让应用程序之间可以共享数据。 4. Telephony Manager:提供了访问手机通讯功能的接口和服务。 5. Location Manager:提供了访问 GPS 和其他位置服务的接口和服务。 6. Notification Manager:提供了管理通知的接口和服务。 7. View System:提供了 Android 应用程序的 UI 界面的渲染和事件处理等功能。 8. Resource Manager:提供了访问 Android 应用程序的资源文件的接口和服务。 9. Window Manager:提供了窗口管理和界面绘制等功能。 10. Activity Manager Service:提供了 Activity Manager 的服务接口。 11. System Server:提供了 Android 系统的核心服务,包括 PackageManager、ActivityManager、WindowManager 等。 以上是 Android Framework 层源码的主要部分,通过阅读 Android Framework 层源码可以深入了解 Android 系统的实现原理和应用程序的开发框架。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值