Android 面试:事件分发8连问

本文深入探讨了Android事件分发机制,从组装责任链到事件在Activity、Window和View中的传递,详细解释了事件如何从WindowManager经由InputDispatcher到达View。文中还分析了在事件到达页面后,如何通过`onInterceptTouchEvent`和`dispatchTouchEvent`判断是否拦截事件,以及子View如何处理事件。最后讨论了滑动冲突的外部拦截法,并提供了模板代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

forward(q);

} else if (shouldDropInputEvent(q)) {

finish(q, false);

} else {

traceEvent(q, Trace.TRACE_TAG_VIEW);

final int result;

try {

result = onProcess(q);

} finally {

Trace.traceEnd(Trace.TRACE_TAG_VIEW);

}

apply(q, result);

}

}

}

如上所示:

1.QueuedInputEvent是一种输入事件,链表结构,遍历传递给InputStage

2.InputStage是处理输入的责任链,在调用deliver时会遍历责任链传递事件

3.事件分发完成后会调用finishInputEvent,告知SystemServer进程的InputDispatcher线程,最终将该事件移除,完成此次事件的分发消费。

那么问题来了,InputStage的责任链是什么时候组件的呢?

[](()2.3 组装责任链

我们得回到ViewRootImpl.setView方法中

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {

synchronized (this) {

// Set up the input pipeline.

mSyntheticInputStage = new SyntheticInputStage();

InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);

InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,

“aq:native-post-ime:” + counterSuffix);

InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);

InputStage imeStage = new ImeInputStage(earlyPostImeStage,

“aq:ime:” + counterSuffix);

InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);

InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,

“aq:native-pre-ime:” + counterSuffix);

mFirstInputStage = nativePreImeStage;

mFirstPostImeInputStage = earlyPostImeStage;

}

}

可以看到在setView方法中,就把这条输入事件处理的责任链拼接完成了,不同的InputStage子类,通过构造方法一个个串联起来了,那这些InputStage到底干了啥呢?

  • SyntheticInputStage。综合处理事件阶段,比如处理导航面板、操作杆等事件。

  • ViewPostImeInputStage。视图输入处理阶段,比如按键、手指触摸等运动事件,我们熟知的view事件分发就发生在这个阶段。

  • NativePostImeInputStage。本地方法处理阶段,主要构建了可延迟的队列。

  • EarlyPostImeInputStage。输入法早期处理阶段。

  • ImeInputStage。输入法事件处理阶段,处理输入法字符。

  • ViewPreImeInputStage。视图预处理输入法事件阶段,调用视图viewdispatchKeyEventPreIme方法。

  • NativePreImeInputStage。本地方法预处理输入法事件阶段。

小结一下,事件到达应用端的主线程,会通过ViewRootImpl进行一系列InputStage来处理事件。这个阶段其实是对事件进行一些简单的分类处理,比如视图输入事件,输入法事件,导航面板事件等等。

我们的View触摸事件就发生在ViewPostImeInputStage阶段

final class ViewPostImeInputStage extends InputStage {

@Override

protected int onProcess(QueuedInputEvent q) {

if (q.mEvent instanceof KeyEvent) {

return processKeyEvent(q);

} else {

final int source = q.mEvent.getSource();

if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {

return processPointerEvent(q);

}

}

}

private int processPointerEvent(QueuedInputEvent q) {

final MotionEvent event = (MotionEvent)q.mEvent;

boolean handled = mView.dispatchPointerEvent(event)

return handled ? FINISH_HANDLED : FORWARD;

}

//View.java

public final boolean dispatchPointerEvent(MotionEvent event) {

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值