IMS之inputDispacther(motion事件的分发) - l-feng/l-feng.github.io GitHub Wiki

上节中说到了InputReader,接下来这节继续inputDispatcher。当事件进入dispatcher的时候,

输入事件其实已经被InputReader加工为三类类型:key事件,motion事件,以及switch事件。

在这三类事件之中,最简单的就是switch事件,它根本没有派发的流程,而是直接将Switch事件

交给了DispatchPolicy处理。接下来说说motion事件的处理流程

一:motion事件

1将事件注入到派发队列中

代码走向:NotifyMotionlocked()------->enqueueInboundEventLocked()

1.1 NotifyMotionlocked()

1)在输入事件进入到派发队列之前,首先向DispatcherPolicy获取本事件的派发策略

2)在进入派发队列之前还有一件重要的事情,就是把事件交给InputFilter进行过滤

3)使用NotifyMotionArgs参数中事件信息构造一个Motionentry,并通过

enqueueInboundEventLocked()函数将其放入到派发队列中

4) 唤醒派发队列

1.2 enqueueInboundEventLocked()

1)如果mInbound为空,则表示此事派发线程处于休眠状态,因此事件注入到mInboundQueue后需要进行唤醒

2) 将事件注入到mInboundQueue的队尾

从上面可以看出,到达InputDispatcher的motion事件被保存在MotionEntry类中,然后排在mInboundQueue

队列的队尾,这个mInboundQueue就是InputDispatcher的派发队列。MotionEntry是EventEntry的一个子类,

保存了motion事件的信息,Key事件也有一个相应的KeyEntry。EventEntry是输入事件在InputDispatcher的

存在形式

2:派发线程的线程循环

dispactcherOnce()------>dispatchOnceInnerLocked()----->dispatchMotionLocked()----->

dispatchEventlocked()

1.1 dispactcherOnce():

1)通过dispatchOnceInnerLocked(&nextWakeupTime)进行事件的派发 其中nextWakeupTime为

LONG_LONG_MIN将使派发线程立刻开始下次线程循环

2)执行队列中的命令

nextWakeupTime=LONG_LONG_MIN;

3)如果有必要,将派发线程进入休眠状态,并由 nextWakeupTime确定休眠的具体时间

Int timeoutMillis =toMillisecondTimeoutdelay(currentTime,nextWakeupTime);

Mlooper->pollOnce(timeoutMillis);

1.2 dispatchOnceInnerLocked():

1 ) 从派发队列中取出一事件进行派发,如果派发队列为空,则会使派发队列陷入无休止的休眠状态

2 ) 检查事件是否需要丢弃,即将被派发的事件从派发队列中取出保存在mPendingEvent中,事件也有

可能因为很多因素被丢弃,被丢弃的原因保存在Dropreason

3 ) 执行DispatchMotionLocked()进行motion事件的分发,在这里不同类型的时间会进行不同的派发函数。

4 ) 如果事件完成,则进行下一个事件分发。派发的事件至少需要一个循环才能完成,是否在下次继续尝试进行

此事件的派发由派发函数决定的。事件的派发是串行的,排在队首的事件完成派发或被丢弃之前,不会进行后面的

派发

在这里就要说下事件被丢弃的原因

1)DROP_REASON_POLICY:某些输入事件具有系统级的功能。如home,挂断的操作,这些事件不会被窗口捕获

2)DROP_REASON_APP_SWITCH:前一个事件的阻塞,后一个事件肯定也会被阻塞掉。

3)DROP_REASON_BLOCKED:窗口无法响应用户操作的时候,用户可以希望在其他窗口多次点击,以尝试是

否有反馈。因为事件是串行的,所以事件会被丢弃

4)DROP_REASON_DISABLED:因为Dispatcher被禁用所以事件被丢弃。当手机进入休眠状态的时候,

Dispatcher会被禁用掉,当手机进入横屏的过程中,Dispatcher会被暂时的冻结

5)DROP_REASON_STALE:如果事件过于陈旧,则会被丢弃,在进行事件的派发的时候,dispatchOnceInnerLocked()

会进行时间的判断。

3 motion 事件目标窗口的确认

代码走向:DispatchMotionlocked()---->DispatchEventLocked()--->prepareDispatchcycleLocked()

3.1 :DispatchMotionlocked()

DispatchMotionlocked()函数专门用来为motion事件寻找合适的目标窗口

该函数主要进行的操作有:

1)对于那些不幸丢弃的事件,直接返回true。

2)根据motion事件的类型,寻找合适的窗口。目标窗口分为两种,普通窗口以及监听窗口,普通窗口值得是按点

查找与按焦点查找两种方式获得,而监听窗口是监听所有的事件。

3)如果成功的找到了可以接收事件的目标窗口,则通过DispatchEventLocked()函数完成实际的派发工作。

3.2 DispatchEventLocked()

1)遍历每一个inputTarget

2)根据inputTarget中的inputChannel,获取每一个connection对象

3)调用prepareDispatchcycleLocked()针对当前的inputTarget启动事件发送循环