前言
查漏补缺,查漏补缺,你不知道哪里漏了,怎么补缺呢?本文属于【Android面试查漏补缺】系列文章第一篇,持续更新中,感兴趣的朋友可以【关注+收藏】哦~
本系列文章是对自己的前段时间面试经历的总结。其实本来自己是不太想继续写关于面试题的文章了,因为社区内很多这类的文章,但是如果每个地方翻一下,又不方便自己回顾,所以还是决定写下本文供自己巩固,也给大家一个参考。
一、题目层次
面试中提到安卓的事件分发,我们一般都能说到从 Activity -> Window -> DecorView -> ViewGroup -> View 的 dispatchTouchEvent 流程,这个是最基本的需要掌握的,由此能深入引出一些什么知识点呢?
事件是如何从屏幕点击最终到达 Activity 的?
CANCEL 事件什么时候会触发?
如何解决滑动冲突?
二、题目详解
2.1 安卓事件的分发
安卓的事件分发大概会经历 Activity -> PhoneWindow -> DecorView -> ViewGroup -> View 的 dispatchTouchEvent。
其中 dispatchTouchEvent 用下面的一段伪代码就可以说明了,过程就不具体分析了,大家应该也都比较清晰。
// 伪代码
public boolean dispatchTouchEvent() {
boolean res = false;
// 是否不允许拦截事件
// 如果设置了 FLAG_DISALLOW_INTERCEPT,不会拦截事件,所以在 child 里可以通过 requestDisallowInterceptTouchEvent 控制父 View 是否来拦截事件
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept && onInterceptTouchEvent()) { // View 不调用这里,直接执行下面的 touchlistener 判断
if (touchlistener && touchlistener.onTouch()) {
return true;
}
res = onTouchEvent(); // 里面会处理点击事件 -> performClick() -> clicklistener.onClick()
} else if (DOWN) { // 如果是 DOWN 事件,则遍历子 View 进行事件分发
// 循环子 View 处理事件
for (childs) {
res = child.dispatchTouchEvent();
}
} else {
// 事件分发给 target 去处理,这里的 target 就是上一步处理 DOWN 事件的 View
target.child.dispatchTouchEvent();
}
return res;
}
2.2 事件是如何到达 Activity 的
既然上面的事件分发是从 Activity 开始的,那事件是怎么到达 Activity 的呢?
总体流程大概是这样的:用户点击设备, linux 内核接受中断, 中断加工成输入事件数据写入对应的设备节点中, InputReader 会监控 /dev/input/ 下的所有设备节点, 当某个节点有数据可以读时,通过 EventHub 将原始事件取出来并翻译加工成输入事件,交给 InputDispatcher,InputDispatcher 根据 WMS 提供的窗口信息把事件交给合适的窗口,窗口 ViewRootImpl 派发事件
大体流程图如下:

其中主要有几个阶段:
- 硬件中断
- InputManagerService 做的事情
- InputReaderThread 做的事情
- InputDispatcherThread 做的事情
- WindowInputEventReceiver 做的事情
2.2.1 硬件中断
硬件中断这里就简单介绍一些,操作系统对硬件事件的接收是通过中断来进行的。
内核启动的时候会在中断描述符表中对中断类型以及对应的处理方法的地址进行注册。
当有中断的时候,就会调用对应的处理方法,把对应的事件写入到设备节点里。
2.2.2 InputManagerService 做的事情
InputManagerService 是用来处理 Input 事件的,Java 侧的 InputManagerService 就是 C++ 代码的一个封装,以及提供了一些 callback 用来传递事件到 Java 层。
我们看一下 native 侧的 InputManagerService 初始化代码。
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
// ...
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}
主要做的两件事:
- 初始化

本文是【Android面试查漏补缺】系列的第一篇,详细阐述了Android事件分发机制,从硬件中断到Activity的dispatchTouchEvent流程,包括InputManagerService、InputReaderThread、InputDispatcherThread的作用,以及CANCEL事件触发条件和解决滑动冲突的方法。

2760

被折叠的 条评论
为什么被折叠?



