当前位置:首页 » 安卓系统 » android事件处理机制

android事件处理机制

发布时间: 2023-01-12 16:08:44

‘壹’ Framework事件机制——手撕Android事件处理的三种方法

Android的事件处理的三种方法:

setOnClickListener,setOnLongClickListener、setOnTouchListener

注意:如果onTouchEvent方法return true,则单击事件和长摁事件不再执行;若onLongClick方法返回true,则单击事件不再处理。

需要定义继承组件的类,重写回调方法Touch方法执行时,先被Activity捕获,DispatchTouchEvent方法处理。return false,交给上层的onTouchEvent方法处理;return super.dispatchTouchEvent(ev),则传递给最外层的View。

View用Dispatch方法处理,return false,由上层的onTouchEvent方法处理。如果返回super.dispatchTouchEvent(ev),则本层的onInterceptTouchEvent拦截,如果拦截true,则拦截,false不拦截,传递给子View的DispatchTouchEvent处理。

常用的回调方法:onKeyDown,onKeyLongPress,onKeyUp,onTouchEvent,onTrackballEvent(轨迹球事件)监听和回调同时存在时,先调用监听。

流程模型图:

Event source 事件源
Event 事件
Event Listener 事件监听器
下面我们来看一下点击事件和触摸事件的监听三要素具体是那部分:

由于点击事件比较简单,系统已经帮我们处理了,并没有找到具体事件是哪个。

View.OnClickListener 单击事件监听器必须实现的接⼝
View.OnCreateContextMenuListener 创建上下⽂菜单事件
View.OnFocusChangeListener 焦点改变事件
View.OnKeyListener 按键事件监听器
View.OnLongClickListener 长按事件监听器
View.OnTouchListener 触摸屏事件监听器

⾸先,事件监听机制中由事件源,事件,事件监听器三类对象组成。
事件监听器处理流程:

在此以OnClickListener单击事件为例使用intent来实现页面的跳转

监听事件处理是事件源与事件监听器分开的而基于回调的事件处理UI组件不但是事件源,而且还是事件监听器,通过组件的相关回调方法处理对应的事件。

Ⅰ. 自定义View类,继承自需要的View UI类。ex :自定义 MyButton按钮类 extends 基础Button类

Ⅱ. 复写回调函数。ex:public boolean onTouchEvent(MotionEvent event)

每一个事件回调方法都会返回一个boolean值,①.如果返回true:表示该事件已被处理,不再继续向外扩散,②.如果返回false:表示事件继续向外扩散

而说到基于回调就离不开监听机制

几乎所有基于回调的事件处理方法都有一个boolean类型的返回值,该返回值用于表示该处理方法是否能完全处理该事件。
如果处理事件的回调方法返回true,表明该处理方法已经完全处理改事件,该事件不会传播出去。
如果处理事件的回调方法返回false,表明该处理方法并未完全处理该事件,该事件会传播出去。
对于基于回调的时间传播而言,某组件上所发生的事件不仅会激发该组件上的回调方法,也会触发该组件所在Activity的回调方法——只要事件能传播到该Activity。

这里是在模拟器里进行的测试,这里按下键盘(而不是点击),会看到 logcat 中的输出,如下:

View类实现了KeyEvent.Callback接口中的一系列回调函数,因此,基于回调的事件处理机制通过自定义View来实现,自定义View时重写这些事件处理方法即可。

Handler是一个消息分发对象。

Handler是Android系统提供的一套用来更新UI的机制,也是一套消息处理机制,可以通过Handler发消息,也可以通过Handler处理消息。

在下面介绍Handler机制前,首先得了解以下几个概念:

在子线程执行完耗时操作,当Handler发送消息时,将会调用 MessageQueue.enqueueMessage ,向消息队列中添加消息。 当通过 Looper.loop 开启循环后,会不断地从消息池中读取消息,即调用 MessageQueue.next , 然后调用目标Handler(即发送该消息的Handler)的 dispatchMessage 方法传递消息, 然后返回到Handler所在线程,目标Handler收到消息,调用 handleMessage 方法,接收消息,处理消息。

从上面可以看出,在子线程中创建Handler之前,要调用 Looper.prepare() 方法,Handler创建后,还要调用 Looper.loop() 方法。而前面我们在主线程创建Handler却不要这两个步骤,因为系统帮我们做了。

初始化Looper

从上可以看出,不能重复创建Looper,每个线程只能创建一个。创建Looper,并保存在 ThreadLocal 。其中ThreadLocal是线程本地存储区(Thread Local Storage,简称TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的TLS区域。

开启Looper

发送消息

post方法:

send方法:

在子线程中,进行耗时操作,执行完操作后,发送消息,通知主线程更新UI。

本文讲解了三个方面;Android事件机制;基于监听、基于回调以及Handler消息处理。还有许多没有讲解到的知识点,我总结在了整理的一套Android进阶笔记里面;需要学习进阶的同学可以前往获取: Frame Work源码解析手册 、 Android核心技术进阶手册、实战笔记、面试题纲资料

‘贰’ Android-View的事件分发及拦截-父控件和子控件都处理触摸事件的方式

比如接着上篇 Android-View的事件分发及拦截机制简单流程先体验再研究(场景?疑问? 具体?待续...) ,小白现在要实现就是子View和父ViewGroup都响应点击事件。

1. 单纯的都只是响应down事件

这个就很简单了 - 直接子View的**public boolean **onTouchEvent(MotionEvent event) 里面直接返回false就行了。也就是子控件响应了一次down后,接下来就交给父ViewGroup了.(子View就啥几把也干不了了);

2. 响应down和up事件,move啥的

我们知道子View如果onTouch里面返回了true,那么将会处理后续的move,up事件。而不再交给上层父ViewGroup。那父ViewGroup就没办法在Touch里面处理,所以我们只能放到dispatchTouchEvent或者onInterceptTouchEvent中处理这个down,up等事件:

比如dispatchTouchEvent中:

这样的情况就是父ViewGroup先执行点击事件,然后子View再执行。 如果您需要父ViewGroup晚点,可以延时执行啥的。

如果此时,子View的dispatchTouchEvent返回true - 表示拦截,不继续了

那么子View的所有的事件都不会响应了。其实也就是我们的一个事件先传递,touch再处理的树形图:

网络上拔个图来

简单记录下下而已,继续加深理解...这是上一篇的续,还是上一篇....啧啧....后面是官方文档分析来着...

‘叁’ Android View 事件分发机制

Android 事件机制包含系统启动流程、输入管理(InputManager)、系统服务和 UI 的通信(WindowManagerService + ViewRootImpl + Window)、事件分发等一系列的环节。

Android 系统中将输入事件定义为 InputEvent,根据输入事件的类型又分为了 KeyEvent(键盘事件) 和 MotionEvent(屏幕触摸事件)。这些事件统一由系统输入管理器 InputManager 进行分发。

在系统启动的时候,SystemServer 会启动 WindowManagerService,WMS 在启动的时候通过 InputManager 来负责监控键盘消息。

InputManager 负责从硬件接收输入事件,并将事件通过 ViewRootImpl 分发给当前激活的窗口处理,进而分发给 View。

Window 和 InputManagerService 之间通过 InputChannel 来通信,底层通过 socket 进行通信。

Android Touch 事件的基础知识:

KeyEvent 对应了键盘的输入事件;MotionEvent 就是手势事件,鼠标、笔、手指、轨迹球等相关输入设备的事件都属于 MotionEvent。

InputEvent 统一由 InputManager 进行分发,负责与硬件通信并接收输入事件。

system_server 进程启动时会创建 InputManagerService 服务。

system_server 进程启动时同时会启动 WMS,WMS 在启动的时候就会通过 IMS 启动 InputManager 来监控键盘消息。

App 端与服务端建立了双向通信之后,InputManager 就能够将产生的输入事件从底层硬件分发过来,Android 提供了 InputEventReceiver 类,以接收分发这些消息:

Window 和 IMS 之间通过 InputChannel 通信。InputChannel 是一个 pipe,底层通过 socket 进行通信。在 ViewRootImpl.setView() 过程中注册 InputChannel。

Android 事件传递机制是 先分发再处理 ,先由外部的 View 接收,然后依次传递给其内层的 View,再从最内层 View 反向依次向外层传递。

三个方法的关系如下:

分发事件:

应用了树的 深度优先搜索算法 (Depth-First-Search,简称 DFS 算法),每个 ViewGroup 都持有一个 mFirstTouchTarget, 当接收到 ACTION_DOWN 时,通过递归遍历找到 View 树中真正对事件进行消费的 Child,并保存在 mFirstTouchTarget 属性中,依此类推组成一个完整的分发链。在这之后,当接收到同一事件序列的其它事件如 ACTION_MOVE、ACTION_UP 时,则会跳过递归流程,将事件直接分发给下一级的 Child。

ViewGroup 分发事件的主要的任务是找一个 Target,并且用这个 Target 处理事件,主要逻辑如下 :

为什么倒序查找 TouchTarget?
如果按添加顺序遍历,当 View 重叠时(FrameLayout),先添加的 View 总是能消费事件,而后添加的 View 不可能获取到事件。

拦截事件:

[1] Android 事件分发机制的设计与实现
[2] Android 事件拦截机制的设计与实现

‘肆’ 请简述什么是android事件处理,并分析两种android事件处理机制的实现过程和区别

Android提供了两种方式的事件处理:基于回调的事件处理和基于监听器的事件处理。
对于基于监听器的事件处理而言,主要就是为Android界面组件绑定特定的事件监听器;对于基于回调的事件处理而言,主要做法是重写Android组件特定的回调函数,Android大部分界面组件都提供了事件响应的回调函数,我们主要重写它们就行。

一 基于监听器的事件处理
相比于基于回调的事件处理,这是更具“面向对象”性质的事件处理方式。在监听器模型中,主要涉及三类对象:
1)事件源Event Source:产生事件的来源,通常是各种组件,如按钮,窗口等。
2)事件Event:事件封装了界面组件上发生的特定事件的具体信息,如果监听器需要获取界面组件上所发生事件的相关信息,一般通过事件Event对象来传递。
3)事件监听器Event Listener:负责监听事件源发生的事件,并对不同的事件做相应的处理。

基于监听器的事件处理机制是一种委派式Delegation的事件处理方式,事件源将整个事件委托给事件监听器,由监听器对事件进行响应处理。这种处理方式将事件源和事件监听器分离,有利于提供程序的可维护性。
举例:
View类中的OnLongClickListener监听器定义如下:(不需要传递事件)

[java] view plainprint?
public interface OnLongClickListener {
boolean onLongClick(View v);
}
public interface OnLongClickListener {
boolean onLongClick(View v);
}

View类中的OnLongClickListener监听器定义如下:(需要传递事件MotionEvent)
[java] view plainprint?
public interface OnTouchListener {
boolean onTouch(View v, MotionEvent event);
}
public interface OnTouchListener {
boolean onTouch(View v, MotionEvent event);
}
二 基于回调的事件处理
相比基于监听器的事件处理模型,基于回调的事件处理模型要简单些,该模型中,事件源和事件监听器是合一的,也就是说没有独立的事件监听器存在。当用户在GUI组件上触发某事件时,由该组件自身特定的函数负责处理该事件。通常通过重写Override组件类的事件处理函数实现事件的处理。
举例:
View类实现了KeyEvent.Callback接口中的一系列回调函数,因此,基于回调的事件处理机制通过自定义View来实现,自定义View时重写这些事件处理方法即可。
[java] view plainprint?
public interface Callback {
// 几乎所有基于回调的事件处理函数都会返回一个boolean类型值,该返回值用于
// 标识该处理函数是否能完全处理该事件
// 返回true,表明该函数已完全处理该事件,该事件不会传播出去
// 返回false,表明该函数未完全处理该事件,该事件会传播出去
boolean onKeyDown(int keyCode, KeyEvent event);
boolean onKeyLongPress(int keyCode, KeyEvent event);
boolean onKeyUp(int keyCode, KeyEvent event);
boolean onKeyMultiple(int keyCode, int count, KeyEvent event);
}
public interface Callback {
// 几乎所有基于回调的事件处理函数都会返回一个boolean类型值,该返回值用于
// 标识该处理函数是否能完全处理该事件
// 返回true,表明该函数已完全处理该事件,该事件不会传播出去
// 返回false,表明该函数未完全处理该事件,该事件会传播出去
boolean onKeyDown(int keyCode, KeyEvent event);
boolean onKeyLongPress(int keyCode, KeyEvent event);
boolean onKeyUp(int keyCode, KeyEvent event);
boolean onKeyMultiple(int keyCode, int count, KeyEvent event);
}
三 比对
基于监听器的事件模型符合单一职责原则,事件源和事件监听器分开实现;
Android的事件处理机制保证基于监听器的事件处理会优先于基于回调的事件处理被触发;
某些特定情况下,基于回调的事件处理机制会更好的提高程序的内聚性。

四 基于自定义监听器的事件处理流程
在实际项目开发中,我们经常需要自定义监听器来实现自定义业务流程的处理,而且一般都不是基于GUI界面作为事件源的。这里以常见的app自动更新为例进行说明,在自动更新过程中,会存在两个状态:下载中和下载完成,而我们的程序需要在这两个状态做不同的事情,“下载中”需要在UI界面上实时显示软件包下载的进度,“下载完成”后,取消进度条的显示。这里进行一个模拟,重点在说明自定义监听器的事件处理流程。

‘伍’ Android ANR 机制

广播的 ANR 处理相对简单,主要是再次判断是否超时、记录日志,记录 ANR 次数等。然后就继续调用 processNextBroadcast 函数,处理下一条广播了。

ContentProvider 超时为 CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10s

Activity 的 ANR 是相对最复杂的,也只有 Activity 中出现的 ANR 会弹出 ANR 提示框。
最终的表现形式是:弹出一个对话框,告诉用户当前某个程序无响应,输入一大堆与 ANR 相关的日志,便于开发者解决问题。

InputDispatching:

Activity 最主要的功能之一是交互,为了方便交互,Android 中的 InputDispatcher 会发出操作事件,最终在 InputManagerService 中发出事件,通过 InputChannel,向 Activity 分发事件。交互事件必须得到响应,如果不能及时处理,IMS 就会报出 ANR,交给 AMS 去弹出 ANR 提示框。

KeyDispatching:

如果输入是个 Key 事件,会从 IMS 进入 ActivityRecord.Token.keyDispatchingTimeOut,然后进入 AMS 处理,不同的是,在 ActivityRecord 中,会先截留一次 Key 的不响应,只有当 Key 连续第二次处理超时,才会弹出 ANR 提示框。

窗口焦点:

Activity 总是需要有一个当前窗口来响应事件的,但如果迟迟没有当前窗口(获得焦点),比如在 Activity 切换时,旧 Activity 已经 onPause,新的 Activity 一直没有 onResume,持续超过 5 秒,就会 ANR。
App 的生命周期太慢,或 CPU 资源不足,或 WMS 异常,都可能导致窗口焦点。

1. 判断是否有 focused 组件以及 focused Application:

这种一般是在应用启动时触发,比如启动时间过长在这过程中触发了 keyevent 或者 trackball moteionevent 就会出现。

对应于

2. 判断前面的事件是否及时完成:

对应于

出现这种问题意味着主线程正在执行其他的事件但是比较耗时导致输入事件无法及时处理。

InputDispatcher 超时是最常见的 ANR 类型,而且其类型也比较多。
当用户触摸屏幕或者按键操作,首次触发的是硬件驱动,驱动收到事件后,将该相应事件写入到输入设备节点, 这便产生了最原生态的内核事件。接着,输入系统取出原生态的事件,经过层层封装后成为 KeyEvent 或者 MotionEvent ;最后,交付给相应的目标窗口(Window)来消费该输入事件。可见,输入系统在整个过程起到承上启下的衔接作用。

Input 模块的主要组成:

每一个应用进程都会有一个 SignalCatcher 线程,专门处理 SIGQUIT,来到 art/runtime/signal_catcher.cc :

当应用发生 ANR 之后,系统会收集许多进程,来 mp 堆栈,从而生成 ANR Trace 文件。收集的第一个,也是一定会被收集到的进程,就是发生 ANR 的进程。接着系统开始向这些应用进程发送 SIGQUIT 信号,应用进程收到 SIGQUIT 后开始 mp 堆栈。

[1] developer ANRs
[2] Android ANR 分析详解
[3] 看完这篇 Android ANR 分析,就可以和面试官装逼了!
[4] 微信 Android 团队手把手教你高效监控 ANR
[5] Input 系统—ANR 原理分析 - Gityuan
[6] 彻底理解安卓应用无响应机制 - Gityuan
[7] 理解 Android ANR 的触发原理 - Gityuan

‘陆’ android的事件处理机制有两种

1.基于监听的事件处理机制,有一个关键就是事件注册。 但是我们在实践的时候并没有自己手动的为某个视图控件注册监听器。
解答: 我们会经常用到 诸如 setOnclickListener(),OnTouchListener()方法等。 从字面意义理解,它为设置...监听器。 但是,它 跟注册还是颇有一些区别的。 我想注册实践监听器,就是将它挂在在一个线程上,也就是说有一个事件监听线程,那么,有事件的视图,就至少是双线程的程序了。 不过很可惜,在去看set..Listener的源码的时候,是看不到它在java源码方面的具体实现的。 也就是说,要么它依赖操作系统实现,要么它依赖jni实现,并且,事件线程由jni管理。 换言之,实现注册监听是由ni实现的。
2.事件源的触发流程:
解答: 学习过操作系统朋友应该知道,操作系统的很多操作都是通过中断来完成。 同理,比如一个点击事件,android手机硬件中,包括了一个触摸屏的硬件,它分为内屏和外屏。 其中负责触发屏幕点击和触摸中断的为内屏。 内屏大概由五个层次构成,具体有什么用不知道,反正我拆过~~~ 从内屏上,当有电容屏感应的时候,会接收到你触摸的位置信息,甚至触摸力度!!! 这个消息经由系统中断(具有最高优先级,应该是由最高优先级的进程通知)发送给cpu,经由cpu通过进程间的消息机制传递给这个进程(当前正在用户界面运行的进程,这时候只有一个),也就是这个程序运行的内存空间的某个点。(或者说通过广播机制,将这个事件发送给所有的app也是有可能的)。

‘柒’ Android 系统运行机制 【Looper】【Choreographer】篇

目录:
1 MessageQueue next()
2 Vsync
3 Choreographer doFrame
4 input

系统是一个无限循环的模型, Android也不例外,进程被创建后就陷入了无限循环的状态

系统运行最重要的两个概念:输入,输出。

Android 中输入 输出 的往复循环都是在 looper 中消息机制驱动下完成的

looper 的循环中, messageQueue next 取消息进行处理, 处理输入事件, 进行输出, 完成和用户交互

应用生命周期内会不断 产生 message 到 messageQueue 中, 有: java层 也有 native层

其中最核心的方法就是 messageQueue 的 next 方法, 其中会先处理 java 层消息, 当 java 层没有消息时候, 会执行 nativePollOnce 来处理 native 的消息 以及监听 fd 各种事件

从硬件来看, 屏幕不会一直刷新, 屏幕的刷新只需要符合人眼的视觉停留机制

24Hz , 连续刷新每一帧, 人眼就会认为画面是流畅的

所以我们只需要配合上这个频率, 在需要更新 UI 的时候执行绘制操作

如何以这个频率进行绘制每一帧: Android 的方案是 Vsync 信号驱动。

Vsync 信号的频率就是 24Hz , 也就是每隔 16.6667 ms 发送一次 Vsync 信号提示系统合成一帧。

监听屏幕刷新来发送 Vsync 信号的能力,应用层 是做不到的, 系统是通过 jni 回调到 Choreographer 中的 Vsync 监听, 将这个重要信号从 native 传递到 java 层。

总体来说 输入事件获取 Vsync信号获取 都是先由 native 捕获事件 然后 jni 到 java 层实现业务逻辑

执行的是 messageQueue 中的关键方法: next

next 主要的逻辑分为: java 部分 和 native 部分

java 上主要是取java层的 messageQueue msg 执行, 无 msg 就 idleHandler

java层 无 msg 会执行 native 的 pollOnce@Looper

native looper 中 fd 监听封装为 requestQueue, epoll_wait 将 fd 中的事件和对应 request 封装为 response 处理, 处理的时候会调用 fd 对应的 callback 的 handleEvent

native 层 pollOnce 主要做的事情是:

vsync 信号,输入事件, 都是通过这样的机制完成的。

epoll_wait 机制 拿到的 event , 都在 response pollOnce pollInner 处理了

这里的 dispatchVsync 从 native 回到 java 层

native:

java:

收到 Vsync 信号后, Choreographer 执行 doFrame

应用层重要的工作几乎都在 doFrame 中

首先看下 doFrame 执行了什么:

UI 线程的核心工作就在这几个方法中:

上述执行 callback 的过程就对应了图片中 依次处理 input animation traversal 这几个关键过程

执行的周期是 16.6ms, 实际可能因为一些 delay 造成一些延迟、丢帧

input 事件的整体逻辑和 vsync 类似

native handleEvent ,在 NativeInputEventReceiver 中处理事件, 区分不同事件会通过 JNI

走到 java 层,WindowInputEventReceiver 然后进行分发消费

native :

java:

input事件的处理流程:

输入event deliverInputEvent

deliver的 input 事件会来到 InputStage

InputStage 是一个责任链, 会分发消费这些 InputEvent

下面以滑动一下 recyclerView 为例子, 整体逻辑如下:

vsync 信号到来, 执行 doFrame,执行到 input 阶段

touchEvent 消费, recyclerView layout 一些 ViewHolder

scroll 中 fill 结束,会执行 一个 recyclerView viewProperty 变化, 触发了invalidate

invalidate 会走硬件加速, 一直到达 ViewRootImpl , 从而将 Traversal 的 callback post choreographer执行到 traversal 阶段就会执行

ViewRootImpl 执行 performTraversal , 会根据目前是否需要重新layout , 然后执行layout, draw 等流程

整个 input 到 traversal 结束,硬件绘制后, sync 任务到 GPU , 然后合成一帧。

交给 SurfaceFlinger 来显示。

SurfaceFlinger 是系统进程, 每一个应用进程是一个 client 端, 通过 IPC 机制,client 将图像显示工作交给 SurfaceFlinger

launch 一个 app:

‘捌’ Android事件分发机制

Android中对视图的Touch事件进行分发处理。
单手指操作:ACTION_DOWN -> ACTION_MOVE -> ACTION_UP
多手指操作:ACTION_DOWN -> ACTION_POINTER_DOWN -> ACTION_MOVE -> ACTION_POINTER_UP -> ACTION_UP.

(1) dispatchTouchEvent() :事件分发

(2) onInterceptTouchEvent() :事件拦截

(3) onTouchEvent() :事件处理

ViewGroup 的相关事件有三个:onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent。

View 的相关事件只有两个:dispatchTouchEvent、onTouchEvent。

先分析ViewGroup的处理流程:首先得有个结构模型概念:ViewGroup和View组成了一棵树形结构,最顶层为Activity的ViewGroup,下面有若干的ViewGroup节点,每个节点之下又有若干的ViewGroup节点或者View节点,依次类推。如图:

点击事件达到顶级 View(一般是一个 ViewGroup),会调用 ViewGroup 的 dispatchTouchEvent 方法,如果顶级 ViewGroup 拦截事件即 onInterceptTouchEvent 返回 true,则事件由 ViewGroup 处理,这时如果 ViewGroup 的 mOnTouchListener 被设置,则 onTouch 会被调用,否则 onTouchEvent 会被调用。也就是说如果都提供的话,onTouch 会屏蔽掉 onTouchEvent。在 onTouchEvent 中,如果设置了 mOnClickListenser,则 onClick 会被调用。如果顶级 ViewGroup 不拦截事件,则事件会传递给它所在的点击事件链上的子 View,这时子 View 的 dispatchTouchEvent 会被调用。如此循环。

‘玖’ Android应用处理MotionEvent的过程

应用对于Motion事件的处理比较复杂,不同类型的事件处理方式不同:

下面从应用UI线程的 Looper 开始分析

下面看 NativeInputEventReceiver 的 handleEvent()

对于 InputEventReceiver 的 dispatchInputEvent() 处理流程,在后文中分析。

下面看 InputConsumer 的 consume() 实现

对于Down事件等直接处理的事件,处理过程相对简单,下面看Batch事件的处理过程。

下面从 NativeInputEventReceiver 的 consumeEvents() 开始分析。

对于Batch的首个Move事件,创建新的Batch,Move事件添加到Batch,然后循环读取,通常返回WOULD_BLOCK(无事件可读)。最终调用 WindowInputEventReceiver 的 () 。

下面看Vsync到来之前,Batch的后续Move事件的处理。

下面仍然从 NativeInputEventReceiver 的 consumeEvents() 开始分析

Batch的后续Move事件的处理相对简单,只是将Move事件添加到Batch,下面分析Vsync信号到来后,Batch事件的处理。

下面从App收到Vsync信号调用 CALLBACK_INPUT 类型的回调 ConsumeBatchedInputRunnable 开始分析。

下面看 consumeEvents() 的处理

无论直接处理还是Batch处理,最终都通过 WindowInputEventReceiver 的 dispatchInputEvent() 处理,下面分析该过程。

下面从 WindowInputEventReceiver 的 OnInputEvent() 开始分析

下面看 deliverInputEvent() 的实现

下面看 EarlyPostImeInputStage 的对 MotionEvent 的处理

EarlyPostImeInputStage 处理完事件后,传递给 NativePostImeInputStage 处理, NativePostImeInputStage 的处理过程非常简单,下面直接看 ViewPostImeInputStage 的处理。

至此,Motion事件已经传递给 Activity ,下面看Motion事件在 Activity 窗口内传递的过程。

下面从 Activity 的 dispatchTouchEvent() 开始分析

下面看 PhoneWindow 的 superDispatchTouchEvent() 的实现

下面分析 ViewGroup 的 dispatchTouchEvent() 实现

‘拾’ Android RecyclerView点击事件处理

Android新引入的RecyclerView用来代替ListView,但是RecyclerView处理点击和长按事件却没有ListView方便
RecyclerView并没有onClickListener和onLongClickListener方法
这样我们就需要在Adapter中创建一个接口

同时在adapter中创建该接口属性

然后在adapter implements OnClickListener,View.OnLongClickListener,在方法onCreateViewHolder中,

在方法onBindViewHolder中,设置

特别注意:这里胡itemView即接受点击事件的view,并不需要在ViewHolder中显式地初始化,当ViewHolder实例化之后,itemView也就自动实例化了。
这样我们在adapter实现的onClick和onLongClick方法中,就可以

最后,在activity中实现接口
即可实现点击事件

热点内容
sqlserver2005命令 发布:2025-07-04 06:27:08 浏览:730
压缩文件啥样 发布:2025-07-04 06:21:42 浏览:297
linux的回车换行 发布:2025-07-04 06:21:39 浏览:131
c语言的窗口 发布:2025-07-04 06:20:54 浏览:982
androidk线图 发布:2025-07-04 06:19:15 浏览:130
华为荣耀6短信加密 发布:2025-07-04 06:18:30 浏览:814
sqlserver2008链接 发布:2025-07-04 06:15:54 浏览:906
ueditor的图片上传 发布:2025-07-04 06:09:09 浏览:539
iis7匿名访问 发布:2025-07-04 05:53:33 浏览:319
ftp服务器被动模式配置 发布:2025-07-04 05:17:32 浏览:334