如图所示,蓝色箭头描述的流程才是UI层级的事件分发。
为了方便理解,本文使用了以下两个词汇:应用整体的事件分发 和 UI层级的事件分发 ——需要重申的是,这两个词汇虽然被分开讲解,但其本质仍然属于一个完整 事件分发的责任链,后者只是前者的一小部分而已。
架构设计
1.InputEvent:输入事件分类概述
Android
系统中将输入事件定义为InputEvent
,而InputEvent
根据输入事件的类型又分为了KeyEvent
和MotionEvent
:
// 输入事件的基类
public abstract class InputEvent implements Parcelable { }
public class KeyEvent extends InputEvent implements Parcelable { }
public final class MotionEvent extends InputEvent implements Parcelable { }
复制代码
KeyEvent
对应了键盘的输入事件,那么什么是MotionEvent
?顾名思义,MotionEvent
就是移动事件,鼠标、笔、手指、轨迹球等相关输入设备的事件都属于MotionEvent
,本文我们简单地将其视为 屏幕触摸事件。
用户的输入种类繁多,由此可见,Android
输入系统的设计中,将 输入事件 抽象为InputEvent
是有必要的。
2.InputManager:系统输入管理器
Android
系统的设计中,InputEvent
统一由系统输入管理器InputManager
进行分发。在这里InputManager
是native
层级的一个类,负责与硬件通信并接收输入事件。
那么InputManager
是如何初始化的呢?这里就要涉及到Java
层级的SystemServer
了,我们知道SystemServer
进程中包含着各种各样的系统服务,比如ActivityManagerService
、WindowManagerService
等等,SystemServer
由zygote
进程启动, 启动过程中对WindowManagerService
和InputManagerService
进行了初始化:
public final class SystemServer {
private void startOtherServices() {
// 初始化 InputManagerService
InputManagerService inputManager = new InputManagerService(context);
// WindowManagerService 持有了 InputManagerService
WindowManagerService wm = WindowManagerService.main(context, inputManager,…);
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
}
}
复制代码
InputManagerService
的构造器中,通过调用native函数,通知native
层级初始化InputManager
:
public class InputManagerService extends IInputManager.Stub {
public InputManagerService(Context context) {
// …通知native层初始化 InputManager
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
}
// native 函数
private static native long nativeInit(InputManagerService service, Context context, MessageQueue messageQueue);
}
复制代码
SystemServer
会启动窗口管理服务WindowManagerService
,WindowManagerService
在启动的时候就会通过InputManagerService
启动系统输入管理器InputManager
来负责监控键盘消息。
对于本文而言,framework
层级相关如WindowManagerService
(窗口管理服务)、native
层级的源码、SystemServer
亦或者 Binder
跨进程通信并非重点,读者仅需了解 系统服务的启动流程 和 层级关系 即可,参考下图:
3.ViewRootImpl:窗口服务与窗口的纽带
InputManager
将事件分发给当前激活的窗口(Window
)处理,这里我们将前者理解为系统层级的 (窗口)服务,将后者理解为应用层级的 窗口, 因此需要有一个中介负责 服务 和 窗口 之间的通信,于是ViewRootImpl
类应运而生。
ViewRootImpl
作为链接WindowManager
和DecorView
的纽带,同时实现了ViewParent
接口,ViewRootImpl
作为整个控件树的根部,它是View
树正常运作的动力所在,控件的测量、布局、绘制以及输入事件的分发都由ViewRootImpl
控制。
那么ViewRootImpl
是如何被创建和初始化的,而 (窗口)服务 和 窗口 之间的通信又是如何建立的呢?
建立通信
1.ViewRootImpl的创建
既然Android
系统将 (窗口)服务 与 窗口 的通信建立交给了ViewRootImpl
,那么ViewRootImpl
必然持有了两者的依赖,因此了解ViewRootImpl
是如何创建的就非常重要。
我们知道,ActivityThread
负责控制Activity
的启动过程,在ActivityThread.performLaunchActivity()
流程中,ActivityThread
会针对Activity
创建对应的PhoneWindow
和DecorView
实例,而在ActivityThread.handleResumeActivity()
流程中,ActivityThrea