房屋建筑图纸设计,网站建设网络推广seo,wordpress一键优化,杭州装饰网站建设方案戳蓝字“CSDN云计算”关注我们哦#xff01;系列前作1. Android输入系统的事件传递流程和IMS的诞生2. 只了解View的事件分发是不够的#xff0c;来看下输入系统对事件的处理1.InputReader的加工类型在只了解View的事件分发是不够的#xff0c;来看下输入系统对事件的处理这篇… 戳蓝字“CSDN云计算”关注我们哦系列前作1. Android输入系统的事件传递流程和IMS的诞生2. 只了解View的事件分发是不够的来看下输入系统对事件的处理1.InputReader的加工类型在只了解View的事件分发是不够的来看下输入系统对事件的处理这篇文章中我们知道InputReader会对原始输入事件进行加工如果事件的类型为按键类型的事件就会调用如下一段代码。frameworks/native/services/inputflinger/InputDispatcher.cppvoid InputDispatcher::notifyKey(const NotifyKeyArgs* args) { ... bool needWake; { ... } // release lock if (needWake) { mLooper-wake(); }}InputDispatcher的notifyKey方法用于唤醒InputDispatcherThread它的参数NotifyKeyArgs是InputReader对按键类型的事件加工后得到的。frameworks/native/services/inputflinger/InputListener.hstruct NotifyKeyArgs : public NotifyArgs { nsecs_t eventTime; int32_t deviceId; uint32_t source; uint32_t policyFlags; int32_t action; int32_t flags; int32_t keyCode; int32_t scanCode; int32_t metaState; nsecs_t downTime; inline NotifyKeyArgs() { } NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime); NotifyKeyArgs(const NotifyKeyArgs other); virtual ~NotifyKeyArgs() { } virtual void notify(const spInputListenerInterface listener) const;};可以看到NotifyKeyArgs结构体继承自NotifyArgs结构体如下图所示。NotifyArgs有三个子类分别是NotifyKeyArgs、NotifyMotionArgs和NotifySwichArgs这说明InputReader对原始输入事件加工后最终会得出三种事件类型分别是key事件、Motion事件和Swich事件这些事件会交由InputDispatcher来进行分发如下图所示。2.InputDispatcher的分发过程不同的事件类型有着不同的分发过程其中Swich事件的处理是没有派发过程的在InputDispatcher的notifySwitch函数中会将Swich事件交由InputDispatcherPolicy来处理。本系列文章一直讲解key事件相关这次换一下以Motion事件的分发过程来进行举例对key事件分发事件有兴趣的可以自行去看源码本质上都差不多。2.1 唤醒InputDispatcherThreadInputDispatcher的notifyMotion函数用来唤醒InputDispatcherThread。frameworks/native/services/inputflinger/InputDispatcher.cppvoid InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {#if DEBUG_INBOUND_EVENT_DETAILS...#endif //检查Motion事件的参数是否有效 if (!validateMotionEvent(args-action, args-actionButton, args-pointerCount, args-pointerProperties)) {//1 return; } uint32_t policyFlags args-policyFlags; policyFlags | POLICY_FLAG_TRUSTED; mPolicy-interceptMotionBeforeQueueing(args-eventTime, /*byref*/ policyFlags); bool needWake; { // acquire lock mLock.lock(); //Motion事件是否需要交由InputFilter过滤 if (shouldSendMotionToInputFilterLocked(args)) {//2 mLock.unlock(); MotionEvent event; //初始化MotionEvent将NotifyMotionArgs中的参数信息赋值给MotionEvent中的参数 event.initialize(args-deviceId, args-source, args-action, args-actionButton, args-flags, args-edgeFlags, args-metaState, args-buttonState, 0, 0, args-xPrecision, args-yPrecision, args-downTime, args-eventTime, args-pointerCount, args-pointerProperties, args-pointerCoords); //表示已经过滤了 policyFlags | POLICY_FLAG_FILTERED; //开始过滤如果返回值为false就会直接return这次事件不再进行分发 if (!mPolicy-filterInputEvent(event, policyFlags)) {//3 return; // event was consumed by the filter } mLock.lock(); } /** * 4 */ MotionEntry* newEntry new MotionEntry(args-eventTime, args-deviceId, args-source, policyFlags, args-action, args-actionButton, args-flags, args-metaState, args-buttonState, args-edgeFlags, args-xPrecision, args-yPrecision, args-downTime, args-displayId, args-pointerCount, args-pointerProperties, args-pointerCoords, 0, 0); needWake enqueueInboundEventLocked(newEntry);//5 mLock.unlock(); } // release lock if (needWake) { mLooper-wake();//6 }}注释1处用于检查Motion事件的参数是否有效其内部会检查触控点的数量pointerCount是否在合理范围内小于1或者大于16都是不合理的以及触控点的ID是否在合理范围内小于0或者大于31都是不合理的。注释2处如果Motion事件需要交由InputFilter过滤就会初始化MotionEvent其作用就是用NotifyMotionArgs中的事件参数信息构造一个MotionEvent接着MotionEven会交给注释3处的方法进行过滤如果返回值为false这次Motion事件就会被忽略掉。注释4处用NotifyMotionArgs中的事件参数信息构造一个MotionEntry对象。注释5处将MotionEntry传入到enqueueInboundEventLocked函数中其内部会将MotionEntry添加到InputDispatcher的mInboundQueue队列的末尾并返回一个值needWake代表InputDispatcherThread是否需要唤醒如果需要唤醒就调用注释6处的代码来唤醒InputDispatcherThread。2.2 InputDispatcher进行分发InputDispatcherThread被唤醒后会执行InputDispatcherThread的threadLoop函数frameworks/native/services/inputflinger/InputDispatcher.cppbool InputDispatcherThread::threadLoop() { mDispatcher-dispatchOnce(); return true;}threadLoop函数中只调用了InputDispatcher的dispatchOnce函数frameworks/native/services/inputflinger/InputDispatcher.cppvoid InputDispatcher::dispatchOnce() { nsecs_t nextWakeupTime LONG_LONG_MAX; { // acquire lock AutoMutex _l(mLock); mDispatcherIsAliveCondition.broadcast(); if (!haveCommandsLocked()) {//1 dispatchOnceInnerLocked(nextWakeupTime);//2 } if (runCommandsLockedInterruptible()) { nextWakeupTime LONG_LONG_MIN; } } // release lock nsecs_t currentTime now();//3 int timeoutMillis toMillisecondTimeoutDelay(currentTime, nextWakeupTime);//4 mLooper-pollOnce(timeoutMillis);}注释1处用于检查InputDispatcher的缓存队列中是否有等待处理的命令如果没有就会执行注释2处的dispatchOnceInnerLocked函数用来将输入事件分发给合适的。注释3处获取当前的时间结合注释4处得出InputDispatcherThread需要睡眠的时间为timeoutMillis。最后调用Looper的pollOnce函数使InputDispatcherThread进入睡眠状态并将它的最长的睡眠的时间设置为timeoutMillis。当有输入事件产生时InputReader就会将睡眠状态的InputDispatcherThread唤醒InputDispatcher会重新开始分发输入事件。查看注释2处的dispatchOnceInnerLocked函数是如何进行事件分发的。frameworks/native/services/inputflinger/InputDispatcher.cppvoid InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { ... // 如果InputDispatcher被冻结则不进行派发操作 if (mDispatchFrozen) {#if DEBUG_FOCUS ALOGD(Dispatch frozen. Waiting some more.);#endif return; } //如果isAppSwitchDue为true说明没有及时响应HOME键等操作 bool isAppSwitchDue mAppSwitchDueTime currentTime;//1 if (mAppSwitchDueTime *nextWakeupTime) {//2 *nextWakeupTime mAppSwitchDueTime; } //如果还没有待分发的事件去mInboundQueue中取出一个事件 if (! mPendingEvent) { //如果mInboundQueue为空并且没有待分发的事件就return if (mInboundQueue.isEmpty()) { ... if (!mPendingEvent) { return; } } else { //如果mInboundQueue不为空取队列头部的EventEntry赋值给mPendingEvent mPendingEvent mInboundQueue.dequeueAtHead(); traceInboundQueueLengthLocked(); } if (mPendingEvent-policyFlags POLICY_FLAG_PASS_TO_USER) { pokeUserActivityLocked(mPendingEvent); } resetANRTimeoutsLocked(); } ALOG_ASSERT(mPendingEvent ! NULL); bool done false; DropReason dropReason DROP_REASON_NOT_DROPPED;//3 ... switch (mPendingEvent-type) {//4 ... case EventEntry::TYPE_MOTION: { MotionEntry* typedEntry static_castMotionEntry*(mPendingEvent); //如果没有及时响应窗口切换操作 if (dropReason DROP_REASON_NOT_DROPPED isAppSwitchDue) { dropReason DROP_REASON_APP_SWITCH; } //事件过期 if (dropReason DROP_REASON_NOT_DROPPED isStaleEventLocked(currentTime, typedEntry)) { dropReason DROP_REASON_STALE; } //阻碍其他窗口获取事件 if (dropReason DROP_REASON_NOT_DROPPED mNextUnblockedEvent) { dropReason DROP_REASON_BLOCKED; } done dispatchMotionLocked(currentTime, typedEntry, dropReason, nextWakeupTime);//5 break; } default: ALOG_ASSERT(false); break; } if (done) { if (dropReason ! DROP_REASON_NOT_DROPPED) { dropInboundEventLocked(mPendingEvent, dropReason); } mLastDropReason dropReason; //释放本次事件处理的对象 releasePendingEventLocked();//6 //使得InputDispatcher能够快速处理下一个分发事件 *nextWakeupTime LONG_LONG_MIN;//7}InputDispatcher的dispatchOnceInnerLocked函数的代码比较长这里截取了和Motion事件的分发相关的主要源码。主要做了以下几件事。InputDispatcher的冻结处理 如果当前InputDispatcher被冻结则不进行派发操作InputDispatcher有三种状态分别是正常状态、冻结状态和禁用状态可以通过InputDispatcher的setInputDispatchMode函数来设置。窗口切换操作处理注释1处的mAppSwitchDueTime 代表了App最近发生窗口切换操作时比如按下Home键、挂断电话该操作事件最迟的分发时间。如果这个时候mAppSwitchDueTime小于等于当前系统时间说明没有及时响应窗口切换操作则isAppSwitchDue的值设置为true。注释2处如果mAppSwitchDueTime小于nextWakeupTime下一次InputDispatcher醒来的时间就将mAppSwitchDueTime赋值给nextWakeupTime这样当InputDispatcher处理完分发事件后会第一时间处理窗口切换操作。取出事件如果没有待分发的事件就从mInboundQueue中取出一个事件如果mInboundQueue为空并且没有待分发的事件就return如果mInboundQueue不为空取队列头部的EventEntry赋值给mPendingEventmPendingEvent的类型为EventEntry对象指针。事件丢弃注释3处的dropReason代表了事件丢弃的原因它的默认值为DROP_REASON_NOT_DROPPED代表事件不被丢弃。注释4处根据mPendingEvent的type做区分处理这里主要截取了对Motion类型的处理。经过过滤会调用注释5处的dispatchMotionLocked函数为这个事件寻找合适的窗口。后续处理如果注释5处的事件分发成功则会在注释6处调用releasePendingEventLocked函数其内部会将mPendingEvent的值设置为Null并将mPendingEvent指向的对象内存释放掉。注释7处将nextWakeupTime的值设置为LONG_LONG_MIN这是为了让InputDispatcher能够快速处理下一个分发事件。后记本文讲解了InputReader的加工类型和InputDispatcher的分发过程由于文章篇幅的原因InputDispatcher的分发过程还有一部分没有讲解这一部分就是事件分发到目标窗口的过程会在本系列的下一篇文章进行讲解。文章转自公众号刘舒望— — — END — — —1.微信群添加小编微信color_ld备注“进群姓名公司职位”即可加入【云计算学习交流群】和志同道合的朋友们共同打卡学习2.征稿投稿邮箱liudancsdn.net微信号color_ld。请备注投稿姓名公司职位。推荐阅读程序员加班很严重吗看看国外程序员怎么怼老板锤子变天| 畅言趣店斗鱼深陷裁员风波程序员寒冬何去何从| 畅言玩过音乐, 推过嫩模, 以太坊大神人设崩塌, 有钱任性也抵不过区块链寒冬【BDTC 2018】PingCAP申砾做一个真正通用的数据库产品谷歌搜索重返中国按下暂停键CEO皮查伊“对决”美国国会↓点击“阅读原文”打开APP 阅读更顺畅