基于Android R版本分析
touch 事件机制
上述的流程在touch事件处理中可以分为两个模块:
- Window窗口拦截消费touch事件;
- View拦截消费touch事件;
上述的判断逻辑在Activity的dispatchTouchEvent()方法中叉分:
/**
* Called to process touch screen events. You can override this to
* intercept all touch screen events before they are dispatched to the
* window. Be sure to call this implementation for touch screen events
* that should be handled normally.
*
* @param ev The touch screen event.
*
* @return boolean Return true if this event was consumed.
*/
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
// 代表了Window窗口中的View子控件消费Touch事件
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
// 如果没有View消费touch事件,则由Window窗口自身消费,调用Activity中的onTouchEvent()
return onTouchEvent(ev);
}
InputStage
onTouchEvent:94, MainActivity (com.example.android.pictureinpicture)
dispatchTouchEvent:4128, Activity (android.app)
dispatchTouchEvent:69, WindowCallbackWrapper (androidx.appcompat.view)
dispatchTouchEvent:446, DecorView (com.android.internal.policy)
dispatchPointerEvent:14568, View (android.view)
processPointerEvent:6022, ViewRootImpl$ViewPostImeInputStage (android.view)
onProcess:5825, ViewRootImpl$ViewPostImeInputStage (android.view)
deliver:5316, ViewRootImpl$InputStage (android.view)
// ViewPostImeInputStage
onDeliverToNext:5373, ViewRootImpl$InputStage (android.view)
forward:5339, ViewRootImpl$InputStage (android.view)
forward:5491, ViewRootImpl$AsyncInputStage (android.view)
apply:5347, ViewRootImpl$InputStage (android.view)
apply:5548, ViewRootImpl$AsyncInputStage (android.view)
deliver:5320, ViewRootImpl$InputStage (android.view)
// NativePostImeInputStage
onDeliverToNext:5373, ViewRootImpl$InputStage (android.view)
forward:5339, ViewRootImpl$InputStage (android.view)
apply:5347, ViewRootImpl$InputStage (android.view)
deliver:5320, ViewRootImpl$InputStage (android.view)
// EarlyPostImeInputStage
deliverInputEvent:8086, ViewRootImpl (android.view)
doProcessInputEvents:8037, ViewRootImpl (android.view)
enqueueInputEvent:7998, ViewRootImpl (android.view)
onInputEvent:8209, ViewRootImpl$WindowInputEventReceiver (android.view)
dispatchInputEvent:220, InputEventReceiver (android.view)
nativePollOnce:-1, MessageQueue (android.os)
next:335, MessageQueue (android.os)
loop:183, Looper (android.os)
main:7666, ActivityThread (android.app)
invoke:-1, Method (java.lang.reflect)
run:592, RuntimeInit$MethodAndArgsCaller (com.android.internal.os)
main:947, ZygoteInit (com.android.internal.os)
上述的流程堆栈中,出现了3次deliver()方法的调用,对应的都是InputStage类的方法,但是每一次的InputStage都对应的不用类型的InputStage;
InputStage代表了输入事件的处理阶段,使用"责任链模式"设计模式;
InputStage 类图
-
AsyncInputStage
- NativePreImeInputStage:本地方法预处理输入法事件阶段(不支持Touch事件);
- NativePostImeInputStage:本地方法处理阶段,主要构建了可延迟的队列(支持Touch事件);
- ImeInputStage:输入法事件处理阶段,处理输入法字符(不支持Touch事件);
-
ViewPreImeInputStage:视图预处理输入法事件阶段,调用视图view的dispatchKeyEventPreIme方法(不支持Touch事件);
-
EarlyPostImeInputStage:输入法早期处理阶段(支持Touch事件);
-
ViewPostImeInputStage:视图输入处理阶段,比如按键、手指触摸等运动事件,我们熟知的view事件分发就发生在这个阶段(支持Touch事件);
-
SyntheticInputStage:综合处理事件阶段,比如处理导航面板、操作杆等事件,未处理 InputEvent最后处理(支持Touch事件);
InputStage流程图
责任链模式的各个InputStage进行说明,整体流程如上所说,简要归纳如下:
-
输入法之前的处理
- NativePreImeInputStage
- ViewPreImeInputStage
-
输入法处理
- ImeInputStage
-
输入法之后处理
- EarlyPostImeInputStage
- NativePostImeInputStage
- ViewPostImeInputStage
-
综合处理
- SyntheticInputStage
InputStage将输入事件的处理分成若干个阶段(Stage),如果当前有输入法窗口,则事件处理从 NativePreIme 开始,否则从EarlyPostIme 开始;
事件依次经过每个Stage,如果该事件没有被标识为 “Finished”, 该Stage就会处理它,然后返回处理结果Forward 或 Finish,Forward 运行下一个Stage继续处理,而Finished事件将会简单的Forward到下一级,直到最后一级 SyntheticInputStage;
Window touch事件流转
自定义Activity中重现onTouchEvent()方法,该方法的调用栈;
可以看到,在截止到ViewPostImeInputStage进行了touch事件的处理之后,不会再向下传递;