Android事件分发分析

本篇所分析的源码为Android 28,可能与其他版本有所出入

流程概括

  1. 输入事件由FrameWork层发送到ViewRootImpl的内部类WindowInputEventReceiver上,根据InputEvent的类型,进行不同的分发方式。
  2. 如果是TouchEventViewRootImpl调用其保存的View.dispatchTouchEvent()方法,这个View一般是DecorView,如果是悬浮窗一类的直接是WindowManagerGlobal.addView()的那个View
  3. DecorView首先将该事件交由Window中的callback进行处理,也就是ActivityDialog
  4. Activity然后在交由Window也就是PhoneWindow处理
  5. PhoneWindow在交由内部保存的DecorView进行处理
  6. DecorView使用ViewGroup分发逻辑向下分发。
  7. ViewGroup首先判断自身是否拦截事件,如果onInterceptTouchEvent返回true,则自身消费事件。
  8. 如果不拦截,则将子View按z-order的顺序排序,根据MotionEvent的x、y寻找子View,将事件分发给它们。
  9. 如果子ViewViewGroup,则同样继续分发给子View
  10. 如果子ViewView,那么通过判断mOnTouchListeneronTouchEvent的返回值看是否事件消费
  11. 如果所有的子View都没有消费这个事件,则事件向上返回,由父ViewGroup决定自身是否消费。
  12. 最终ActivityWindow都不消费,则ViewRootImpl调用finishInputEvent结束本次事件。
阅读更多

Android焦点机制

本篇所分析的源码为Android 28,可能与其他版本有所出入

焦点存储与设置

焦点的标志位

View中,自身的许多状态都是使用mPrivateFlags来记录,其中FOCUSABLE_MASK位为记录View的焦点状态

View.java
1
2
3
4
/**
* Mask for use with setFlags indicating bits used for focus.
*/
private static final int FOCUSABLE_MASK = 0x00000011;

View的焦点焦点状态共有3种NOT_FOCUSABLEFOCUSABLEFOCUSABLE_AUTO

View.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* This view does not want keystrokes.
*/
public static final int NOT_FOCUSABLE = 0x00000000;

/**
* This view wants keystrokes.
*/
public static final int FOCUSABLE = 0x00000001;

/**
* This view determines focusability automatically. This is the default.
*/
public static final int FOCUSABLE_AUTO = 0x00000010;

其中FOCUSABLE_AUTO为默认状态,当未在xml未配置android:focusable属性时,系统会将焦点状态设置为FOCUSABLE_AUTO

阅读更多

Android的TouchMode

什么是TouchMode

TouchMode就是”触摸模式“。在一般情况下,Android系统都是处于TouchMode的模式下也就是View.isInTouchMode() == true的状态下。大多Android开发都是开发的手机App应用,所以可能没有接触或使用过TouchMode,而在开发Android TV应用或其他没有触摸屏的应用时会接触到这个TouchMode,但一旦使用遥控器遥控或调用了View.requestFocusFromTouch等可以更改TouchMode的方法后,系统就会退出TouchMode,当用户点击屏幕后,就会进入触屏模式也就是TouchMode模式。

阅读更多