事件分发机制(一)--Activity

444 阅读2分钟

「这是我参与11月更文挑战的第23天,活动详情查看:2021最后一次更文挑战

1. 被分发的对象

按下、滑动、抬起、取消这几种事件组成了一个事件流。事件流以按下为开始,中间可能有若干次滑动,以抬起或取消作为结束。

事件触发场景触发次数(次)
MotionEvent.ACTION_DOWN按下1
MotionEvent.ACTION_MOVE滑动0或多
MotionEvent.ACTION_UP抬起0或1
MotionEvent.ACTION_CANCLE滑动超出控件边界0或1

2. 事件分发

  • 用户的按键行为->手机传感器->ViewRootImpl->DecorView->WindowCallbackWrapper->Activity->PhoneWindow->DecorView->ViewGroup*->View->程序员的代码逻辑->硬件(显示器、扬声器等)响应输出->用户感知
  • ViewRootImpl是Android层逻辑起始点,用于接收来自系统底层的事件消息。相当于View管理类,本身不是View
  • DecorView是Android View树的根节点,持有window对象。本身能够直接进行真正事件分发能力,但是事件分发会直接调用window,间接传递到Activity的事件分发,后续会由Activity回调DecorView的真正事件分发能力

事件分发.png

3. Activity 的事件分发

首先会将点击事件传递到 Activity 中,具体是执行dispatchTounchEvent() 进行事件分发 Activity.png

所以,想要理解Android 分发机制,本质上要理解:

  • Activity 点击事件的分发机制
  • ViewGroup 点击事件的分发机制
  • View 点击事件的分发机制
Activity.dispatchTouchEvent() 源码分析

(1) 如果 getWindow().superDispatchTouchEvent(ev) 的返回为 true , 则 Activity.dispatchTouchEvent() 就返回true , 方法结束。即 :该点击事件停止往下传递,事件传递过程结束;否则继续往下调用Activity.onTouchEvent()

// Activity.dispatchTouchEvent()
public boolean dispatchTouchEvent(MotionEvent ev) {
  . . .
  if (getWindow().superDispatchTouchEvent(ev)) {
    return true;
  }
  return onTouchEvent(ev);
}

我们再看 getWindow().superDispatchTouchEvent(ev) ,getWindow() 是获取 Window 类的对象,它的唯一实现类是 PhoneWindow 类

// PhoneWindow
public boolean superDispatchTouchEvent(MotionEvent event) {
  return mDecor.superDispatchTouchEvent(event);
}

DecorView 类是 PhoneWindow 类的一个内部类,它继承 FrameLayout,是所有界面的父类,FrameLayout 是 ViewGroup 的子类,所以 DecorView 的间接父类等于 ViewGroup

// DecorView
public boolean superDispatchTouchEvent(MotionEvent event) {
  return super.dispatchTouchEvent(event);
}
Activity.onTouchEvent() 源码分析

当一个点击事件未被Activity下任何一个View接收/处理时,就会调用 Activity.onTouchEvent()

// Activity.onTouchEvent()
public boolean onTouchEvent(MotionEvent event) {
  if (mWindow.shouldCloseOnTouch(this, event)) {
    finish();
    return true;
  }
  return false;
}

当点击事件在Window边界外会返回true