| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> android 触摸事件流转流程 -> 正文阅读 |
|
[移动开发]android 触摸事件流转流程 |
Iput 子系统https://www.cnblogs.com/Ph-one/p/4849558.html inputReader?https://www.jianshu.com/p/34f5c7d55337 InputDispatcher分发事件https://www.jianshu.com/p/6e250a8ff80c 1、InputReader获取事件,最终InputReader将input event放到InputDispatcher的mInboundQueue后唤醒InputDispacher。 2、InputDispacher从mInboundQueue头部取出事件交给dispatchKeyLocked执行分发处理 3、事件处理需要找到目标窗口mFocusedWindowHandle,findFocusedWindowTargetsLocked将焦点窗口与inputTargets建立InputChannel联系 4、InputDispatcher::dispatchEventLocked根据inputTargets的InputChannel对应的fd 从mConnectionsByFd中找到connection 5、将事件发送到inputTargets,其实等于做了一次搬运的工作,将InputDispatcher中mInboundQueue中的eventEntry事件取出后, 找到目标window后,将eventEntry封装dispatchEntry加入到connection的outboundQueue队列。 6、InputDispatcher::startDispatchCycleLocked中通过InputPublisher将DispatchEntry发送给窗口,再将DispatchEntry从outboundQueue移到waitQueue里。该通信过程是异步的,当窗口处理完事件后会通过handleReceiveCallback()回调函数通知InputDispatcher::handleReceiveCallback。 7、通过connection 的InputChannel 发送事件到对应窗口 InputChannelhttps://www.jianshu.com/p/b09afd403f71 InputDispatcher通过publishKeyEvent把input事件发送给客户端,InputDispatcher是属于system_server进程,而客户端属于应用进程,两种通信属于跨进程通信,分析下system_server与应用建立通信的过程。
2、frameworks/native/libs/input/InputTransport.cpp InputTransport?中会创建socketpair对,一个是服务端套接字,一个是客户端套接字。 3、frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java 应用在setView()的是会调用IWindowSession的addToDisplay()函数。这是添加窗口流程,它包含了App与SurfaceFlinger服务建立连接的部分,也是包含了InputChannel建立连接的部分。它本身是个binder调用,服务端是WMS,最终调用的是WMS的addWindow方法。 InputChannel通过InputChannel.openInputChannelPair分别窗建一对InputChannel,然后将Server端的InputChannel注册到InputDispatcher中,将Client端的InputChannel返回给客户端应用。socket pair的创建过程这里不详细说,简单总结下:openInputChannelPair 生成了两个Socket的fd, 代表一个双向通道的两端。初始化了两端的包括Native层和Java层的InputChannel对象,InputChannel封装了name和fd。 frameworks/native/services/inputflinger/InputDispatcher.cpp Server端的InputChannel注册到InputDispatcher中 ? ? 一个Connection 对象被创建出来,这个Connection表示客户端和服务端的一个输入数据通道,每个Connection都对应一个服务端的InputChannel,每个服务端的InputChannel又对应一个socket pair的fd。InputDispatcher用fd为索引,将所有的Connection保存在mConnectionByFd中,再将这个fd注册在InputDispatcher的Looper的监控列表里,这样一旦对端(客户端)的socket写入数据,Looper就会被唤醒,接着就会调用回调函数handleReceiveCallback。另外,一个Dispatcher可能有多个Connection(多个Window)同时存在。 4、client端获取客户端的socket fd inputChannels[1].transferTo(outInputChannel); 这个outInputChannel是客户端setView创建的,当参数传递过来的。这里很就是将client端的fd传给outInputChannel。 在setView中会创建WindowInputEventReceiver对象,构造方法会调用super,在其父类InputEventReceiver的构造方法中会执行nativeInit,最终执行如下代码: frameworks/base/core/jni/android_view_InputEventReceiver.cpp ? 此处的Looper便是应用主线程的Looper,将socket客户端的fd添加到应用线程的Looper来监听,当服务端有事件,触发回调方法NativeInputEventReceiver::handleEvent()。 至此,socket正式建立连接。 InputEventReceiver 接收事件处理 https://www.cnblogs.com/TaigaCon/p/4750349.html Android应用处理MotionEvent的过程 https://www.jianshu.com/p/c2e26c6d4ac1 https://blog.csdn.net/fisher_2005/article/details/76423409 https://www.jianshu.com/p/bc4c9e5f4b1c ? ? ? ? 打印log: InputReader: dispatchTouches action DOWN now(ns) InputEventReceiver: channel '4893658 com.android.launcher3/com.android.launcher3.Launcher (client)' ~ Consuming input events, consumeBatches=false, frameTime=-1 InputTransport: channel '4893658 com.android.launcher3/com.android.launcher3.Launcher (client)' consumer ~ consume: consumeBatches=false, frameTime=-1 InputTransport: channel '4893658 com.android.launcher3/com.android.launcher3.Launcher (client)' consumer ~ consumed motion event, seq=1925 InputEventReceiver: channel '4893658 com.android.launcher3/com.android.launcher3.Launcher (client)' ~ Dispatching input event. ? ? 打印 ?Dispatching batched input event pending notification ? frameworks\base\core\java\android\view\InputEventReceiver.java private void dispatchBatchedInputEventPending() { ? frameworks\base\core\java\android\view\ViewRootImpl.java final class WindowInputEventReceiver extends InputEventReceiver { void scheduleConsumeBatchedInput() { ? 对应channel 'WindowManager (client)' 是InputEventReceiver中方法 frameworks\base\core\java\android\view\InputEventReceiver.java 打印log: InputReader: dispatchTouches action DOWN now(ns): InputEventReceiver: channel '4893658 com.android.launcher3/com.android.launcher3.Launcher (client)' ~ Consuming input events, consumeBatches=false, frameTime=-1 InputTransport: channel '4893658 com.android.launcher3/com.android.launcher3.Launcher (client)' consumer ~ consume: consumeBatches=false, frameTime=-1 InputTransport: channel '4893658 com.android.launcher3/com.android.launcher3.Launcher (client)' consumer ~ started batch event InputEventReceiver: channel '4893658 com.android.launcher3/com.android.launcher3.Launcher (client)' ~ Dispatching batched input event pending notification. ? ? ? 打印log: InputReader: dispatchTouches action MOVE now(ns): InputEventReceiver: channel '4893658 com.android.launcher3/com.android.launcher3.Launcher (client)' ~ Consuming input events, consumeBatches=false, frameTime=-1 InputTransport: channel '4893658 com.android.launcher3/com.android.launcher3.Launcher (client)' consumer ~ consume: consumeBatches=false, frameTime=-1 09-26 15:51:57.219 19960 19960 D InputTransport: channel '4893658 com.android.launcher3/com.android.launcher3.Launcher (client)' consumer ~ appended to batch event 等待Vsync 到来时,调用mConsumedBatchedInputRunnable ?
Vsync 到来,执行mInputEventReceiver.consumeBatchedInputEvents,这里会分发事件,也最后调到doProcessInputEvents()。如果条件满足则执行scheduleConsumeBatchedInput()为下个Vsync准备Choreographer.CALLBACK_INPUT?消息 doProcessInputEvents();?再次分发处理事件,一般这个时候事件队列为空 如果事件队列事件不为空,就会分发事件,并在trace 中有deliverInputEvent?标签 ? ? ? ? ? http://www.masonchang.com/blog/2014/8/25/androids-touch-resampling-algorithm 帧绘制60Hz,屏刷新扫描100Hz,从而底层上报move 事件是10ms(10?pixels) ,重采样频率是11ms。 ? ? 事件内插处理 Vsync 到来时,如果采样时间点附近一个事件在采样点之前,一个在采样点跟Vsync之间,则将这两个事件做内插处理。 ?vsync t=32 ms,?st=27 ms,则t1=20 ms 和?t2=30 ms?两个事件 ? ? Alpha 越大,越接近第二个事件;越小越接近第一个事件。 事件外插处理 vsync t=48,st= 43ms,则t1=30?ms 和?t2=40?ms?两个事件 ? 重采样处理的结果:事件如下,除了第一个事件,都是16ms 一个事件。 ? ? 514-484=30 30*0.3=9 484 + 9 = 493 432.494 - 409 = 23.494 23.494 * 0.242 = 5.566 432.494 + ?5.566 = 438 Choreographer?Vsnc控制https://www.jianshu.com/p/47c866f6fb67 事件java层分发? https://blog.csdn.net/a992036795/article/details/51690303 https://www.jianshu.com/p/1c44bc932970 https://www.jianshu.com/p/bc4c9e5f4b1c ? ? ? View分为两种,第一种可以有子View的直接或者间接继承ViewGroup,另一种不允许有子View的,直接或者间接继承View的,如TextView,ImageView等等。 每个Activity包含一个window,每个window都是一个phoneWindow,每个PhoneWindow包含一个DecorView,每一个DecorView都是一个Framelayout,Framelayout继承ViewGroup,ViewGroup继承View。 直接继承View 控件事件处理,如TextView 可以重写onTouchEvent和dispatchTouchEvent,另外setOnTouchListener可以设置onTouch,setOnClickListener可以设置onClick。
3、onTouchEvent?系统默认返回true;如果返回false,表示该View 不处理事件,后续的ACTION_MOVE、ACTION_UP就不会执行dispatchTouchEvent。 默认事件执行: 第一组Action=0:ACTION_DOWN事件,从输出结果可以看出,执行顺序为了dispatchTouchEvent->onTouch->onTouchEvent。 第二组Action=1:ACTION_UP事件,执行顺序与之前相同,但是在末尾多了一个onClick onTouch 返回true 第一组Action=0:ACTION_DOWN事件,从输出结果可以看出,执行顺序为了dispatchTouchEvent->onTouch结束了,后面的onTouchEvent没有再执行。 第二组??Action=2:ACTION_MOVE事件,与ACTION_DOWN事件事件的执行顺序相同。 第二组??Action=1:ACTION_UP事件,与ACTION_DOWN事件事件的执行顺序相同。 onTouchEvent 返回false 执行顺序变成dispatchTouchEvent->onTouch->onTouchEvent,但是整个事件分发过程中,只ACTION_DOWN响应,之后的事件都不再响应。当 onTouchEvent(event)返回false时,result也就返回false了,这个时候就代表dispatchEvent没有消费事件,后续的Action也就不会再执行了。这是因为这个view 没要加入事件处理目标链表。 长按跟click 都是在onTouchEvent中处理的。 ? ViewGroup事件 在ViewGroup当中涉及到事件分发的方法,相比View来说除了dispatchTouchEvent和onTouchEvent外还有onInterceptTouchEvent(默认返回false,不拦截)。 FrameLayout 中有一个TextView 点击TextView 事件响应:
ViewGroup的事件分发与dispatchTouchEvent、onTouchEvent、onInterceptTouchEvent三个方法有关,但是从这个例子当中我们发现所执行的方法只有dispatchTouchEvent和onInterceptTouchEvent,那么onTouchEvent在什么时候执行呢?我们设置的OnTouch方法以及OnClick方法在什么时候调用呢? 当点击TextView 外FrameLayout区域 同样的还是以不同的Action来分组分析:
? 以为Down 事件会执行onInterceptTouchEvent,后面由于没找到view,mFirstTouchTarget 是null,所以之后就不执行onInterceptTouchEvent。 ? ? |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年2日历 | -2025/2/5 20:21:51- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |