在线客服
扫描二维码
下载博学谷APP
扫描二维码
关注博学谷微信公众号
事件是先到DecorView还是先到Window?答案是显而易见的,事件当然是先到DecorView。为什么呢?这就需要我们弄清楚DecorView、PhoneWindow和Activity/Dialog之间传递的顺序,下面我们来看看Input系统、Framework层、DecorView和Activity的相关内容,相信大家就能理解事件先到DecorView的本质原因了。

1、Input系统
当用户触摸屏幕或者按键操作,首次触发的是硬件驱动,驱动收到事件后,将该相应事件写入到输入设备节点,这便产生了最原生态的内核事件。接着,输入系统取出原生态的事件,经过层层封装后成为KeyEvent或者MotionEvent ;最后,交付给相应的目标窗口(Window)来消费该输入事件。
(1)当屏幕被触摸,Linux内核会将硬件产生的触摸事件包装为Event存到/dev/input/event[x]目录下。
(2)Input系统—InputReader线程:loop起来让EventHub调用getEvent()不断的从/dev/input/文件夹下读取输入事件。然后转换成EventEntry事件加入到InputDispatcher的mInboundQueue。
(3)Input系统—InputDispatcher线程:从mInboundQueue队列取出事件,转换成DispatchEntry事件加入到connection的outboundQueue队列。再然后开始处理分发事件 (比如分发到ViewRootImpl的WindowInputEventReceiver中),取出outbound队列,放入waitQueue.
(4)Input系统—UI线程:创建socket pair,分别位于”InputDispatcher”线程和focused窗口所在进程的UI主线程,可相互通信。
2、Framework层
//InputEventReceiver.dispachInputEvent()
private void dispatchInputEvent(int seq, InputEvent event) {
mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event);
}
Native层通过JNI执行Framework层的InputEventReceiver.dispachInputEvent(),而真正调用的是继承了InputEventReceiver的ViewRootImpl.WindowInputEventReceiver。所以这里执行的WindowInputEventReceiver的dispachInputEvent():
final class WindowInputEventReceiver extends InputEventReceiver {
public void onInputEvent(InputEvent event) {
enqueueInputEvent(event, this, 0, true);
}
...
}
ViewRootImpl
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
...
if (processImmediately) {
//关键点:执行Input事件
doProcessInputEvents();
} else {
//走一遍Handler延迟处理事件
scheduleProcessInputEvents();
}
}
void doProcessInputEvents() {
while (mPendingInputEventHead != null) {
QueuedInputEvent q = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
if (mPendingInputEventHead == null) {
mPendingInputEventTail = null;
}
q.mNext = null;
mPendingInputEventCount -= 1;
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);
long eventTime = q.mEvent.getEventTimeNano();
long oldestEventTime = eventTime;
if (q.mEvent instanceof MotionEvent) {
MotionEvent me = (MotionEvent)q.mEvent;
if (me.getHistorySize() > 0) {
oldestEventTime = me.getHistoricalEventTimeNano(0);
}
}
mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
//关键点:进一步派发事件处理
deliverInputEvent(q);
}
...
}
private void deliverInputEvent(QueuedInputEvent q) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
q.mEvent.getSequenceNumber());
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}
InputStage stage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (stage != null) {
//关键点:上面决定将事件派发到那个InputStage中处理
stage.deliver(q);
} else {
finishInputEvent(q);
}
}
ViewRootImpl.ViewPostImeInputStage
前面事件会派发到ViewRootImpl.ViewPostImeInputStage中处理,它的父类InputStage.deliver()方法会调用apply()来处理Touch事件:
protected 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) {
//关键点:执行分发touch事件
return processPointerEvent(q);
} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
return processTrackballEvent(q);
} else {
return processGenericMotionEvent(q);
}
}
}
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
...
//关键点:mView分发Touch事件,mView就是DecorView
boolean handled = mView.dispatchPointerEvent(event);
maybeUpdatePointerIcon(event);
maybeUpdateTooltip(event);
...
}
3、DecorView
如果你熟悉安卓的Window,Activity和Dialog对应的ViewRootImpl成员mView就是DecorView,View的dispatchPointerEvent()代码如下:
//View.java
public final boolean dispatchPointerEvent(MotionEvent event) {
if (event.isTouchEvent()) {
//分发Touch事件
return dispatchTouchEvent(event);
} else {
return dispatchGenericMotionEvent(event);
}
}
因为DecorView继承FrameLayout,上面所以会调用DecorView的dispatchTouchEvent():
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final Window.Callback cb = mWindow.getCallback();
return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
上面Window.Callback都被Activity和Dialog实现,所以变量cb可能就是Activity和Dialog。
4、Activity
当上面cb是Activity时,执行Activity的dispatchTouchEvent():
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {//关键点:getWindow().superDispatchTouchEvent(ev)
return true;
}
return onTouchEvent(ev);
}
如果你熟悉安卓的Window,Activity的getWindow()拿到的就是PhoneWindow,下面是PhoneWindow的代码:
//PhoneWindow.java
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
//调用DecorView的superDispatchTouchEvent
return mDecor.superDispatchTouchEvent(event);
}
下面是DecorView.superDispatchTouchEvent()代码:
//DecorView.java
public boolean superDispatchTouchEvent(MotionEvent event) {
//调用ViewGroup的dispatchTouchEvent()开始我们常见的分发Touch事件
return super.dispatchTouchEvent(event);
}
因为解耦的原因,所以要DecorView -> Activity -> PhoneWindow -> DecorView传递事件。ViewRootImpl并不知道有Activity这种东西存在!它只是持有了DecorView。所以,不能直接把触摸事件送到Activity.dispatchTouchEvent();不直接分发给DecorView,而是要通过PhoneWindow来间接发送也是因为Activity不知道有DecorView!但是,Activity持有PhoneWindow ,而PhoneWindow当然知道自己的窗口里有些什么了,所以能够把事件派发给DecorView。在Android中,Activity并不知道自己的Window中有些什么,这样耦合性就很低了。不管Window里面的内容如何,只要Window仍然符合Activity制定的标准,那么它就能在Activity中很好的工作。当然,这就是解耦所带来的扩展性的好处。
看到这里,想必大家对于事件是先到DecorView还是先到Window已经有了自己的答案了。如果觉得本文对你有所帮助,不妨把文章分享出去让更多的人看到。
— 申请免费试学名额 —
在职想转行提升,担心学不会?根据个人情况规划学习路线,闯关式自适应学习模式保证学习效果
讲师一对一辅导,在线答疑解惑,指导就业!
相关推荐 更多
面试中经常遇到的问题(上)HR都会问什么?
大部分面试官的一些开局面试题是大同小异的。然而,许多求职者未能利用这个众所周知的事实并事先做好准备,而紧张和手足无措。虽然每个公司都有自己的特点,但事先做一些准备了解更多公司信息,会让面试变得更轻松。
17634
2019-08-08 09:59:29
做编程真的需要掌握多种语言吗?
之前就有人讨论过,是否做编程需要掌握多种编程语言呢?很多人各执一词,都有道理。从职业发展的宽度和深度来说,掌握多种编程语言,可能更好的适应企业的发展需要。从而发挥更加重要的作用。而精专主攻一门语言,做到深度学习,成为该领域的专业是不错的发展。下面分享一下两个观点支持者的意见吧。
13360
2019-08-08 12:00:39
简述CPU中断响应过程的九大步骤
本文就CPU中断响应过程的九个步骤进行简单讲述,希望大家都能通过本文大致了解中断响应过程。
26245
2019-08-05 12:06:15
IT行业发展前景怎么样?现在入行是否还有机会?
IT行业发展前景怎么样?其实这个问题大部分都了解,国内近些年来互联网飞速发展,为整个就业市场增加了非常多的就业岗位。由IT行业衍生出来的各种互联网产品极大的改变了人们的生活方式。而这两年云计算、人工智能、大数据、区块链等概念的兴起,为IT行业的发展再次增加强劲的动力。
9394
2019-08-07 18:25:32
5G时代大公司需要什么IT技能?
5G时代大公司需要什么IT技能?如今5G时代已经来临,互联网的迭代升级促进了IT行业的进一步发展,与此同时IT产业为了适应新的技术的变化,也需要不断调整最新的IT技能。
7991
2020-06-03 14:37:06
