在Android系统中,点击事件的处理过程可以分为以下几个主要阶段,从底层的 InputReader 读取输入事件,到 InputDispatcher 分发事件,再到应用进程的 View 进行事件分发。以下是详细的流程:
1. 事件读取 (InputReader)
类名:InputReader
方法:loopOnce()
-
InputReader运行在EventHub线程中,它会从/dev/input读取触摸屏事件(如EV_ABS,EV_KEY)。 -
InputReader::processEventsLocked()解析触摸事件,构建MotionEvent,并传递给InputDispatcher。
2. 事件分发 (InputDispatcher)
类名:InputDispatcher
方法:dispatchOnce()
-
InputDispatcher运行在InputDispatcherThread线程中,它从InputReader获取MotionEvent并进行分发。 -
InputDispatcher::enqueueInboundEventLocked()将事件放入队列。 -
InputDispatcher::dispatchOnceInnerLocked()负责遍历 窗口管理器 (WMS) 的窗口栈,并找到对应的窗口 (Window)。 -
InputDispatcher::dispatchMotionLocked()通过Binder机制调用InputChannel.sendMessage()将事件发送给目标应用进程。
3. 跨进程通信 (应用进程接收事件)
类名:InputChannel,InputEventReceiver
方法:dispatchInputEvent()
-
InputChannel是 Android 跨进程通信的通道,它在InputDispatcher和 应用进程的 UI 线程 之间传输MotionEvent。 -
InputEventReceiver::handleEvent()监听InputChannel的事件,并通过NativeInputEventReceiver传递到ViewRootImpl。
注意,这里跨进程采用的是socketpair:
public final class InputMethodManagerService extends IInputMethodManager.Stub
implements Handler.Callback {
void requestClientSessionLocked(ClientState cs) {
if (!cs.sessionRequested) {
if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
final InputChannel serverChannel;
final InputChannel clientChannel;
{
final InputChannel[] channels = InputChannel.openInputChannelPair(cs.toString());
serverChannel = channels[0];
clientChannel = channels[1];
}
cs.sessionRequested = true;
}
}
public final class InputChannel implements Parcelable {
public static InputChannel[] openInputChannelPair(String name) {
InputChannel channels[] = new InputChannel[2];
long[] nativeChannels = nativeOpenInputChannelPair(name);
for (int i = 0; i< 2; i++) {
channels[i] = new InputChannel();
channels[i].setNativeInputChannel(nativeChannels[i]);
}
return channels;
}
}
static jlongArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
jclass clazz, jstring nameObj) {
std::unique_ptr<InputChannel> serverChannel;
std::unique_ptr<InputChannel> clientChannel;
status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
}
status_t InputChannel::openInputChannelPair(const std::string& name,
std::unique_ptr<InputChannel>& outServerChannel,
std::unique_ptr<InputChannel>& outClientChannel) {
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
status_t result = -errno;
ALOGE("channel '%s' ~ Could not create socket pair. errno=%s(%d)", name.c_str(),
strerror(errno), errno);
outServerChannel.reset();
outClientChannel.reset();
return result;
}
...
}
4. 事件进入 View 层 (ViewRootImpl)
类名:ViewRootImpl
方法:dispatchInputEvent()
-
ViewRootImpl是 View 层的入口点,它会调用ViewRootImpl::deliverInputEvent() - 事件最终由
ViewRootImpl::XXXInputStage::processPointerEvent()处理,并传递给mView,即DecorView。最终会调用DecorView::dispatchTouchEvent - XXXInputStage根据类型不一样类名不一样
private void dispatchInputEvent(int seq, InputEvent event) {
mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event);
}
...
handled = handled || mView.dispatchPointerEvent(event);
...
class View {
public final boolean dispatchPointerEvent(MotionEvent event) {
if (event.isTouchEvent()) {
return dispatchTouchEvent(event);
} else {
return dispatchGenericMotionEvent(event);
}
}
}
5. 事件传递到 DecorView
类名:DecorView
方法:dispatchTouchEvent()
-
DecorView继承自FrameLayout,是整个窗口的根 View。 - 事件先经过
DecorView::dispatchTouchEvent(),这个函数会调用mWindow(PhoneWindow)的callback回调, 这个callback回调就是Activity
public boolean dispatchTouchEvent(MotionEvent ev) {
final Window.Callback cb = mWindow.getCallback();
return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
6. 事件传递到 Activity
类名:Activity
方法:dispatchTouchEvent()
-
Activity默认会将事件传递给Window,然后交给ViewGroup处理:public boolean dispatchTouchEvent(MotionEvent ev) { if (getWindow().superDispatchTouchEvent(ev)) { return true; } return onTouchEvent(ev); } - 其中
getWindow().superDispatchTouchEvent(ev)会调用DecorView::superDispatchTouchEvent(ev)
public boolean superDispatchTouchEvent(MotionEvent event) {
// 这里就是调用Viewgroup的dispatchTouchEvent
return super.dispatchTouchEvent(event);
}
7. 事件传递到 ViewGroup
类名:ViewGroup
方法:dispatchTouchEvent()
-
ViewGroup::dispatchTouchEvent()负责将事件分发给子View:public boolean dispatchTouchEvent(MotionEvent ev) { if (onInterceptTouchEvent(ev)) { return super.dispatchTouchEvent(ev); } return child.dispatchTouchEvent(ev); } -
onInterceptTouchEvent(ev)用于拦截事件。
8. 事件传递到最终的 View
类名:View
方法:dispatchTouchEvent()
-
View::dispatchTouchEvent()先调用onTouchListener监听器,如果没有被消费,则调用onTouchEvent():public boolean dispatchTouchEvent(MotionEvent event) { if (onTouchListener != null && onTouchListener.onTouch(this, event)) { return true; } return onTouchEvent(event); } -
onTouchEvent()处理点击、滑动等事件,默认返回false,表示未消费事件,会向上传递。
9. 事件回溯 (事件未被消费)
- 如果
View没有消费事件,ViewGroup会继续查找其他View处理。 - 如果没有
View处理事件,ViewGroup::onTouchEvent()可能会处理,例如ScrollView可能会消费滑动事件。 - 如果
ViewGroup也没有消费事件,最终回到Activity::onTouchEvent(),然后可能触发onBackPressed()或finish()。
总结
-
InputReader读取触摸事件。 -
InputDispatcher处理并分发事件。 -
InputChannel通过Socket机制发送事件到应用进程。 -
ViewRootImpl作为入口,处理事件并传递到DecorView。 -
DecorView->Activity->Window->ViewGroup->View,层层分发。 -
View通过dispatchTouchEvent()->onTouchListener->onTouchEvent()处理点击事件。
这个过程涵盖了 Android 触摸事件从 内核 到 应用层 的完整传递路径。