Android InputEventReceiver事件接收流程分析

本文基于Android 12。

InputEvent经过inputflinger读取后,通过Inputchannel发送到Java层的InputEventReceiver对象,输入事件和View的状态强相关,事件发送需要确定当前的焦点App,焦点Window(View),事件接收者是谁,所以InputEventReceiver对象也在View的创建流程中被初始化,ViewRootImpl中通过InputChannel参数实例化WindowInputEventReceiver,其覆盖了父类InputEventReceiver的onInputEvent()方法。

一、WindowInputEventReceiver

    // ViewRootImpl.java    
    	final class WindowInputEventReceiver extends InputEventReceiver {
            public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
                super(inputChannel, looper);
            }
          
            @Override
            public void onInputEvent(InputEvent event) {
                    enqueueInputEvent(event, this, 0, true);
            }
        }

调用enqueueInputEvent方法。

    // ViewRootImpl.java 
        QueuedInputEvent mPendingInputEventHead;
    
        void enqueueInputEvent(InputEvent event,
                InputEventReceiver receiver, int flags, boolean processImmediately) {
            QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
            QueuedInputEvent last = mPendingInputEventTail;
            if (last == null) {
                mPendingInputEventHead = q;
                mPendingInputEventTail = q;
            } else {
                last.mNext = q;
                mPendingInputEventTail = q;
            }
            mPendingInputEventCount += 1;
            doProcessInputEvents();
        }

enqueueInputEvent对事件通过mPendingInputEventHead变量维护一个事件队列,doProcessInputEvents()进行下一步处理。

    // ViewRootImpl.java 
    	void doProcessInputEvents() {
            while (mPendingInputEventHead != null) {
                QueuedInputEvent q = mPendingInputEventHead;
                mPendingInputEventHead = q.mNext;
                if (mPendingInputEventHead == null) {
                    mPendingInputEventTail = null;
                }
                q.mNext = null;
              	deliverInputEvent(q);
            }
        }

doProcessInputEvents对mPendingInputEventHead队列中所有事件进行分发。

    // ViewRootImpl.java     
    	private void deliverInputEvent(QueuedInputEvent q) {
            try {
              	InputStage stage;
                if (q.shouldSendToSynthesizer()) {
                    stage = mSyntheticInputStage;
                } else {
                    stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
                }
                if (stage != null) {
                    handleWindowFocusChanged();
                    stage.deliver(q);
                } else {
                    finishInputEvent(q);
                }
            }
        }

将事件交给InputStage处理,InputStage是Android实现事件责任链的基类,deliver()方法中处理是否传递给下一个阶段:forward(),或者结束事件的传递:finish()。

二、InputState

    // ViewRootImpl.java 
    abstract class InputStage {        
        public final void deliver(QueuedInputEvent q) {
            if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
                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);
            }
        }
    }

InputStage是一个抽象类,deliver方法中调用了onProcess(q),子类覆盖onProcess方法实现自己的操作逻辑。

在ViewRootImpl的setView方法中定义了InputState的责任链:

    // ViewRootImpl.java 
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
            int userId) {
            // Set up the input pipeline.
            CharSequence counterSuffix = attrs.getTitle();
            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;
    }

从实例化的顺序可知事件传递阶段的流程:

nativePreImeStage->viewPreImeStage->imeStage->earlyPostImeStage->nativePostImeStage->viewPostImeStage->mSyntheticInputStage

关于各个InputStage的官方说明:

InputStateDescription
NativePreImeInputStageDelivers pre-ime input events to a native activity. Does not support pointer events.
ViewPreImeInputStageDelivers pre-ime input events to the view hierarchy. Does not support pointer events.
ImeInputStageDelivers input events to the ime. Does not support pointer events.
EarlyPostImeInputStagePerforms early processing of post-ime input events.
NativePostImeInputStageDelivers post-ime input events to a native activity.
ViewPostImeInputStageDelivers post-ime input events to the view hierarchy.
SyntheticInputStagePerforms synthesis of new input events from unhandled input events.

可参考文章:https://blog.csdn.net/vviccc/article/details/93377708

一般用户接触到最多的Activity和View属于ViewPostImeInputStage阶段。

三、ViewPostImeInputStage

    // ViewRootImpl.java 
    	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);
                    } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
                        return processTrackballEvent(q);
                    } else {
                        return processGenericMotionEvent(q);
                    }
                }
            }
        }

processKeyEvent处理KeyEvent,MotionEvent有两种情况,触屏操作的MotionEvent调用processPointerEvent处理,轨迹球操作的MotionEvent调用processTrackballEvent处理。

接着查看processPointerEvent方法:

    // ViewRootImpl.java 
    private int processPointerEvent(QueuedInputEvent q) {
        final MotionEvent event = (MotionEvent)q.mEvent;
        boolean handled = mView.dispatchPointerEvent(event);
        maybeUpdatePointerIcon(event);
        maybeUpdateTooltip(event);
        return handled ? FINISH_HANDLED : FORWARD;
    }

调用mView.dispatchPointerEvent(event)方法。

    // View.java    
    	@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
        public final boolean dispatchPointerEvent(MotionEvent event) {
            if (event.isTouchEvent()) {
                return dispatchTouchEvent(event);
            } else {
                return dispatchGenericMotionEvent(event);
            }
        }

终于到了熟悉的dispatchTouchEvent(event)方法。接下来就是熟悉onInterceptTouchEvent(),onTouchEvent()。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值