安卓系统输入事件分发模块和应用进程之间的传递是通过socket,应用在接受到之后其实也是借助Looper机制把输入事件包装成一个消息,丢进消息队列,然后再通过view树分发到具体的控件去处理。本文介绍下应用进程接受到事件之后传递到Acitivty的过程。
重要类图
接收事件
安卓应用进程在NativeInputEventReceiver中接受InputDispatcher发送的输入事件,然后在通过层层调用会构造一个消息丢进消息队列等待处理。下面看看具体的源码
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
// 调用consumeEvents处理消息
status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr);
return KEEP_CALLBACK;
}
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
// 这里会调用java层的ViewRootImpl.dispatchInputEvent方法
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
}
我们接着看ViewRootImpl.dispatchInputEvent方法
public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
// 这里构造消息,然后放进消息队列
SomeArgs args = SomeArgs.obtain();
args.arg1 = event;
args.arg2 = receiver;
Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
分发事件
接下来看看消息的处理过程,这个消息怎么一步一步分发到Actiity的。 上面说过把Input事件封装成消息之后会丢进消息队列,然后交给ViewRootHandler来处理,
final class ViewRootHandler extends Handler {
private void handleMessageImpl(Message msg){
case MSG_DISPATCH_INPUT_EVENT: {
SomeArgs args = (SomeArgs) msg.obj;
InputEvent event = (InputEvent) args.arg1;
InputEventReceiver receiver = (InputEventReceiver) args.arg2;
enqueueInputEvent(event, receiver, 0, true);
args.recycle();
} break;
}
}
// 通常情况下processImmediately为true
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
if (processImmediately) {
doProcessInputEvents();
} else {
scheduleProcessInputEvents();
}
}
void doProcessInputEvents() {
// 循环从PendingInputEvent 取出事件进一步分发
while (mPendingInputEventHead != null) {
QueuedInputEvent q = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
if (mPendingInputEventHead == null) {
mPendingInputEventTail = null;
}
q.mNext = null;
// 这里接下来会依次调用
//ViewPostImeInputStage.processPointerEvent
//DecorView.dispatchTouchEvent(MotionEvent ev)
//Activity.dispatchTouchEvent
deliverInputEvent(q);
}
}
在Activity内的分发
Input事件传到Activity之后,接下来怎么在Activity中的view树中传递。一棵view树总的来说分为两种对象,一个viewgroup, 一个view. Activity, ViewGroup, View三个对象都有dispatchTouchEvent, onTouchEvent函数,ViewGroup多一个onInterceptTouchEvent函数。 Input事件在这三个对象内的传输过程是:
- Activity在dispatchTouchEvent函数中会把事件传递给ViewGroup, 如果ViewGroup没有处理,那么Activity会在onTouchEvent函数中处理这个事件
- viewGroup会在dispatchTouchEvent函数中会把事件传递给View,如果View没有处理,那么ViewGroup会在onInterceptTouchEvent函数中决定是否需要拦截这个事件,如果拦截了,就会在onTouchEvent函数中处理这个事件, 如果不拦截,就会把事件交给Activity去处理。
- View接收到事件之后会在onTouchEvent函数中处理这个事件, 如果没有处理,就会把事件原路返回给ViewGroup去处理。
参考
安卓14源码