【朝花夕拾】Android自定义View篇之(六)Android事件分发机制(中)从源码分析事件分发逻辑及经常遇到的一些“诡异”现象

前言

       转载请注明,转自【https://www.cnblogs.com/andy-songwei/p/11039252.html】谢谢!

       在上一篇文章【【朝花夕拾】Android自定义View篇之(五)Android事件分发机制(上)Touch三个重要方法的处理逻辑】【下文简称(五),请先阅读完(五)再阅读本文】,我们通过示例和log来分析了Android的事件分发机制。这些,我们只是看到了现象,如果要进一步了解事件分发机制,这是不够的,我们还需要透过现象看本质,去研究研究源码。本文将从源码(基于Android API-26)出发,去分析我们上一篇文章中看到的现象,以及其它一些和事件相关的常见问题,如:事件是如何传到View中的、requestDisallowInterceptTouchEvent为什么失效、view设置了focusable=“false”,为什么还能触发点击事件、Touch事件和Click事件谁先谁后等!

      本文的主要内容如下:

 

一、事件的前世今生

       前文中研究事件传递是从Activity的dispatchTouchEvent开始的,但是事件的起源肯定不是Activity。因为触摸事件是触摸的硬件,所以很明显事件一定是从底层传过来的。但是,事件是如何传递到View的呢?这一节我们简单了解一下事件传递到Activity的经过。

       首先,我们在ViewInner类的dispatchTouchEvent方法中打印调用栈,看看这个方法的调用流程。

1 //=============ViewInner.java============
2 @Override
3 public boolean dispatchTouchEvent(MotionEvent event) {
4      Log.i("songzheweiwang",Log.getStackTraceString(new Throwable()));
5      return super.dispatchTouchEvent(event);
6 }

点击ViewInner区域,得到如下log:

 1 java.lang.Throwable
 2     at com.example.demos.customviewdemo.ViewInner.dispatchTouchEvent(ViewInner.java:24)
 3     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3043)
 4     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2727)
 5     at com.example.demos.customviewdemo.ViewGroupMiddle.dispatchTouchEvent(ViewGroupMiddle.java:23)
 6     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3043)
 7     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2727)
 8     at com.example.demos.customviewdemo.ViewGroupOuter.dispatchTouchEvent(ViewGroupOuter.java:23)
 9     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3043)
10     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2727)
11     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3043)
12     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2727)
13     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3043)
14     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2727)
15     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3043)
16     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2727)
17     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3043)
18     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2727)
19     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3043)
20     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2727)
21     at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:526)
22     at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1830)
23     at android.app.Activity.dispatchTouchEvent(Activity.java:3410)
24     at com.example.demos.customviewdemo.EventDemoActivity.dispatchTouchEvent(EventDemoActivity.java:37)
25     at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:68)
26     at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:475)
27     at android.view.View.dispatchPointerEvent(View.java:12768)
28     at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5455)
29     at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:5258)
30     at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4766)
31     at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4819)
32     at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4785)
33     at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4934)
34     at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4793)
35     at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4991)
36     at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4766)
37     at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4819)
38     at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4785)
39     at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4793)
40     at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4766)
41     at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:7490)
42     at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:7448)
43     at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:7409)
44     at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7593)
45     at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:199)
46     at android.os.MessageQueue.nativePollOnce(Native Method)
47     at android.os.MessageQueue.next(MessageQueue.java:326)
48     at android.os.Looper.loop(Looper.java:165)
49     at android.app.ActivityThread.main(ActivityThread.java:7477)
50     at java.lang.reflect.Method.invoke(Native Method)
51     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:500)
52     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:865)

       实际上,Android输入事件的源头是位于/dev/input/下的设备节点,而输入事件的终点是由WMS管理的某个窗口,最终由窗口中的View处理。最初的输入事件为内核生成的原始事件,而最终交付给窗口的则是KeyEvent(键盘)或MotionEvent(鼠标和触摸屏)对象。上述log中(从下往上看),用三种颜色标注了3个阶段:红色部分表示底层活动,这里我们看到了不少熟悉的身影,ZygoteInit,ActivityThread,Native Method等;绿色部分第45行的InputEventReceiver.dispatchInputEvent()方法,事件通过该方法由Native层进入到Java层,并传递到Activity中,这里我们也看到了不少熟悉的身影,ViewRootImpl,DecorView等;从第24行开始,就是我们前面熟悉的,从Acitivty开始调用dispatchTouchEvent一层层来分发事件。可能读者看到从第20~9行会有疑惑,为什么中间还有这么多过程?如果了解Android的View层次结构的话就会知道,在DecorView和开发者定义的布局(如ViewGroupOuter)之间,隔着很多层ViewGroup,也需要一层层传递,这一点我在本系列第一篇【【朝花夕拾】Android自定义View篇之(一)View绘制流程】【后面简称(一)】的第二节做过讲解,不明白的可以先去看看。

       本文的重点是从Activity开始的事件分发,至于前面从底层到Activity的事件流程,咱们这里做一定的了解即可,有兴趣的可以自行研究。

   

二、事件从Activity到View体系

       在上一篇文章的代码示例中,我们的Boss——EventDemoActivity类中有如下代码

 1 //=============Boss:EventDemoActivity.java============
 2  @Override
 3  public boolean dispatchTouchEvent(MotionEvent ev) {
 4      Log.i("songzheweiwang", "[EventDemoActivity-->dispatchTouchEvent]ev=" + EventUtil.parseAction(ev.getAction()));
 5      return super.dispatchTouchEvent(ev);
 6  }
 7 
 8  @Override
 9  public boolean onTouchEvent(MotionEvent event) {
10      Log.i("songzheweiwang", "[EventDemoActivity-->onTouchEvent]event=" + EventUtil.parseAction(event.getAction()));
11      return super.onTouchEvent(event);
12  }

      Activity是事件的起点,disp

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值