Android InputEventReceiver事件接收流程分析

news/2025/2/23 2:37:50/

本文基于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);}@Overridepublic 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 {@Overrideprotected 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()。

文章来源:https://blog.csdn.net/qq_36063677/article/details/130476234
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ppmy.cn/news/57757.html

相关文章

Chapter4:频率响应法(上)

第四章:频率响应法 Exercise4.1 已知微分网络和积分网络电路图如下图所示,求网络的频率特性。 解: 【图 ( a ) ({\rm a}) (a)微分网络】 由微分网络电路图可得:

PMP/高项 05-项目进度管理

项目进度管理 概念 项目进度管理(Schedule Management) 项目进度管理又叫项目工期管理(Duration Management)或项目的时间管理(Time Management) 是一种为管理项目按时完成项目所需的各个过程 进度管理过程 规划进度管理 定义活动 排列活动顺序 估算活…

24:若所有参数皆需类型转换,请为此采用non-member函数

令class支持隐式类型转换通常是个糟糕的主意。 这条规则有其例外,最常见的例外是在建立数值类型时。 例,假设你设计一个class用来表现有理数,则允许整数“隐式转换”为有理数就很合理。 class Rational{ public:Rational(int numerator0,i…

Listener监听器

什么是监听器? 监听器是Servlet规范中的一员。就像Filter一样。Filter也是Servlet规范中的一员。 在Servlet中,所有的监听器接口都是以“Listener”结尾。 监听器有什么用? 监听器实际上是Servlet规范留给我们javaweb程序员的特殊时机。 特殊…

shell脚本的判断式

文章目录 shell脚本的判断式利用test命令的测试功能关于某个文件名的【文件类型】判断关于文件的权限检测两个文件之间的比较关于两个整数之间的比较判定字符串的数据多重条件判定例题 利用判断符号[ ]例题 shell脚本的默认变量($0、$1...)例题shift:造成参数变量号…

docker运行PostgreSQL数据库维护,执行脚本备份数据库与更新表结构

文章目录 PostgreSQL简介业务场景数据库维护docker-compose配置备份脚本更新表结构脚本 PostgreSQL简介 PostgreSQL是一种开源的关系型数据库管理系统,它是一个功能强大、高度可定制化和支持复杂应用的数据库。它支持广泛的数据类型,包括数值、文字、二…

Java基础--->JVM(1)

文章目录 为什么学习JVM?什么是虚拟机?JVM的作用JVM组成部分类加载器类什么时候会被加载(初始化)有哪些类加载器什么是双亲委派机制如何打破双亲委派机制 为什么学习JVM? ​ 学习JVM是为了能更深入的理解Java这门语言&…

python-pandas库

目录 目录 目录 1.pandas库简介(https://www.gairuo.com/p/pandas-overview) 2.pandas库read_csv方法(https://zhuanlan.zhihu.com/p/340441922?utm_mediumsocial&utm_oi27819925045248) 1.pandas库简介(http…