经验总结---Android事件分发机制及设计思路

如图所示,蓝色箭头描述的流程才是UI层级的事件分发。

为了方便理解,本文使用了以下两个词汇:应用整体的事件分发UI层级的事件分发 ——需要重申的是,这两个词汇虽然被分开讲解,但其本质仍然属于一个完整 事件分发的责任链,后者只是前者的一小部分而已。

架构设计

1.InputEvent:输入事件分类概述

Android系统中将输入事件定义为InputEvent,而InputEvent根据输入事件的类型又分为了KeyEventMotionEvent

// 输入事件的基类
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进行分发。在这里InputManagernative层级的一个类,负责与硬件通信并接收输入事件。

那么InputManager是如何初始化的呢?这里就要涉及到Java层级的SystemServer了,我们知道SystemServer进程中包含着各种各样的系统服务,比如ActivityManagerServiceWindowManagerService等等,SystemServerzygote进程启动, 启动过程中对WindowManagerServiceInputManagerService进行了初始化:

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会启动窗口管理服务WindowManagerServiceWindowManagerService在启动的时候就会通过InputManagerService启动系统输入管理器InputManager来负责监控键盘消息。

对于本文而言,framework层级相关如WindowManagerService(窗口管理服务)、native层级的源码、SystemServer 亦或者 Binder跨进程通信并非重点,读者仅需了解 系统服务的启动流程层级关系 即可,参考下图:

3.ViewRootImpl:窗口服务与窗口的纽带

InputManager将事件分发给当前激活的窗口(Window)处理,这里我们将前者理解为系统层级的 (窗口)服务,将后者理解为应用层级的 窗口, 因此需要有一个中介负责 服务窗口 之间的通信,于是ViewRootImpl类应运而生。

ViewRootImpl作为链接WindowManagerDecorView的纽带,同时实现了ViewParent接口,ViewRootImpl作为整个控件树的根部,它是View树正常运作的动力所在,控件的测量、布局、绘制以及输入事件的分发都由ViewRootImpl控制。

那么ViewRootImpl是如何被创建和初始化的,而 (窗口)服务窗口 之间的通信又是如何建立的呢?

建立通信

1.ViewRootImpl的创建

既然Android系统将 (窗口)服务窗口 的通信建立交给了ViewRootImpl,那么ViewRootImpl必然持有了两者的依赖,因此了解ViewRootImpl是如何创建的就非常重要。

我们知道,ActivityThread负责控制Activity的启动过程,在ActivityThread.performLaunchActivity()流程中,ActivityThread会针对Activity创建对应的PhoneWindowDecorView实例,而在ActivityThread.handleResumeActivity()流程中,ActivityThrea

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值