文章前提:
- 了解WMS基本作用
- 了解window的概念,phoneWindow,rootViewImpl
- 了解view的事件分发
开始:
讲三件事情:
- window的创建,更新
- 焦点的更新
- 事件的分发
Window的创建,更新:
window的创建:
最终都是通过和WMS通信完成的。
WMS管理着window的增,删,改以及window层级的管理(Z-order的堆栈管理...),因此window的创建我们自然就联想到了WMS。
在performLaunchActivity()方法中,也就是在 Activity 的启动过程中的几乎最后一步执行:
调用activity.attch()方法
创建PhoneWindow
在handleResumeActivity()处理onResume(),因此在performLaunchActivity后面执行,在这个方法中调用了addView方法:
这个addView由WindowManagerGloal实现,其中创建RootViewImpl,并进行setView()
WindowManagerGloal:
这个root就是RootViewImpl,接下来到setView方法中
通过addToDisPlayAsUser方法调用,
在其中调用WMS的addWindow方法:
此时终于到了WMS的addWindow方法中,这里面做了四件事:
- 窗口检查
- token处理
- windowState的创建
- displayContent的创建和配置
执行完后,由WMS直接和SurfaceFlinger通信,进行显示,此时我们的window就显示出来了。
window的更新:
什么情况下会出现window的更新?
键盘出现,窗口需要重新计算布局并更新显示内容。
只是api执行的不同,不过逻辑同样,app进程发起更新请求,由WindowManagerGlobal进行处理,这个类和WMS通过IWindowSession进行通信,实现更新操作。
焦点的更新:
焦点的基本概念
- 焦点(Focus):UI元素获得焦点后,能够接收用户输入事件,如按键和触摸事件。
- 默认焦点:当一个Activity启动时,系统会自动为某个可交互的控件设置默认焦点。
焦点的获取和失去
- 获取焦点:一个视图可以通过调用
requestFocus()
方法来请求获取焦点。 - 失去焦点:一个视图可以通过调用
clearFocus()
方法来主动放弃焦点。
焦点的移动
- 键盘导航:用户可以使用方向键(如上、下、左、右)在可获得焦点的视图之间导航。
- Tab顺序:使用
android:nextFocusUp
,android:nextFocusDown
,android:nextFocusLeft
,android:nextFocusRight
属性来指定焦点导航的顺序。
处理焦点冲突
- focusable属性的合理使用:确保只有需要交互的视图设置为可获得焦点。
- 自定义焦点顺序:通过XML属性或代码来明确设置焦点导航顺序,避免焦点在不合理的视图之间跳转。
OK,开始焦点机制的部分:
文章前提:
- 了解InputManagerService
- 了解WMS
- 了解RootViewImpl
想要使得焦点更新,需要操作:
分为两种:
requestFocus()
有外部点击
requestFocus:
会通过Binder,通过WMS,WMS中会判断焦点是否更新。
外部点击:
SurfaceFlinger接收到点击之后,通过InputChannel,发送给WMS,WMS内持有所有window的集合,会判断是否需要更新window焦点,通过WMS,surfaceFlinger得知需要更新的window之后,直接通知对应的window的RootViewImpl,通知DecorView,通知Activity,通知PhoneWindow,通知DecorView,然后继续向下分发......下面就是老生常谈的view事件分发机制了......