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结束本次事件。
阅读更多

Handler机制

本篇所分析的源码为Android 28

Handler经常被用于异步消息通知延时任务处理

在子线程中处理数据后,此时需要在UI线程回显数据,在主线程创建Handler对象后,子线程通过Handler.sendMessage()方法发送到handler的处理队列中,在handleMessage()方法中做相应的处理。

延时任务通过postDelayed()方法,一定时间后执行传入的Runnable对象。

源码分析

Handler中的关键类为Looper,其提供了一个MessageQueue消息队列,无论是将要发送的message还是执行的runnable都会被封装为Meassage类压入消息队列中,Looper中通过loop()方法中的死循环,根据压入的时间或延时时间,顺序分发队列中的消息。

阅读更多

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

阅读更多