设为首页 加入收藏

TOP

Android事件分发-基础原理和场景分析(一)
2023-07-23 13:28:46 】 浏览:86
Tags:Android

作者:京东零售 郭旭锋

1 为什么需要事件分发

和其他平台类似,Android 中 View 的布局是一个树形结构,各个 ViewGroup 和 View 是按树形结构嵌套布局的,从而会出现用户触摸的位置坐标可能会落在多个 View 的范围内,这样就不知道哪个 View 来响应这个事件,为了解决这一问题,就出现了事件分发机制。

2 事件分发的关键方法

Android 中事件分发是从 Activity 开始的,可以看看各组件中事件分发的关键方法

Activity:没有 onInterceptTouchEvent 方法,因为如果 Activity 拦截事件,将导致整个页面都没有响应,而 Activity 是系统应用和用户交互的媒介,不能响应事件显然不是系统想要的结果。所以 Activity 不需要拦截事件。

ViewGroup:三个方法都有,Android 中 ViewGroup 是一个布局容器,可以嵌套多个 ViewGroup 和 View,事件传递和拦截都由 ViewGroup 完成。

View:事件传递的最末端,要么消费事件,要么不消费把事件传递给父容器,所以也不需要拦截事件。

3 事件分发流程分析

3.1 事件分发流程概览

Activity 并不是一个 View,那么 Activity 是如何将事件分发到页面的 ViewGroup 和 View 的呢。我们先看看源码

# Activity
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        onUserInteraction();
    }
    // 调用 Window 对象的方法,开始事件分发
    if (getWindow().superDispatchTouchEvent(ev)) {
        return true;
    }
    // 如果事件分发返回 false,也即事件没被消费,则调用自己的 onTouchEvent 方法
    return onTouchEvent(ev);
}

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



可以看到,Activity 中的事件分发方法 dispatchTouchEvent 调用了 getWindow().superDispatchTouchEvent(ev) 方法,而这里的 WIndow 实际上是 PhoneWindow。

简单来说,Window 是一个抽象类,是所有视图的最顶层容器,视图的外观和行为都归他管,无论是背景显示、标题栏还是事件处理都是他管理的范畴,而 PhoneWindow 作为 Window的唯一亲儿子(唯一实现类),自然就是 View 界的皇帝了。

下来看看 PhoneWindow 的代码

# PhoneWindow
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
    return mDecor.superDispatchTouchEvent(event);
}



PhoneWindow 中又调用了 mDecor.superDispatchTouchEvent(event) 方法。mDecor 是 DecorView 对象,再看看 DecorView 的代码

# DecorView
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
    public boolean superDispatchTouchEvent(MotionEvent event) {
        return super.dispatchTouchEvent(event);
    }
}

# FrameLayout
public class FrameLayout extends ViewGroup {
}

# ViewGroup
public abstract class ViewGroup extends View implements ViewParent, ViewManager {
    public boolean dispatchTouchEvent(MotionEvent ev) {
        ......
    }
}

# View
public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {
    public boolean dispatchTouchEvent(MotionEvent ev) {
        ......
    }
}



可以看到,DecorView 实际上就是 ViewGroup,事件分发方法最终调用到了 ViewGroup 的 dispatchTouchEvent(MotionEvent ev) 方法。

DecorView 是 PhoneWindow 的一个对象,其职位就是跟在 PhoneWindow 身边专业为 PhoneWindow 服务的,除了自己要干活之外,也负责消息的传递,PhoneWindow 的指示通过 DecorView 传递给下面的 View,而下面 View 的信息也通过 DecorView 回传给 PhoneWindow。

Android 中的事件分发是责任链模式的一种变形。事件由上往下传递,如果事件没有被消费则继续传递到下一层,如果事件被消费则停止传递,如果到最下层事件则没有被消费,则事件会层层传递给上一层处理。我们都知道事件分发的源头在 Activity 中的 dispatchTouchEvent 方法中,事件从这里开始,分发到布局中的各个 View 中,不断递归调用 ViewGroup/View 的 dispatchTouchEvent 方法。通过上面分析可以看到,Activity 在接受到上层派发来的事件后,会把事件传递到自己的 dispatchTouchEvent 方法中,然后Activity 会把触摸、点击事件传递给自己的 mWindow 对象,最终传递给 DecorView 的 dispatchTouchEvent 方法,实际调用的是 ViewGroup 的 dispatchTouchEvent 方法。

3.2 事件分发源码分析

经过分析,可以知道 Android 中事件分发的关键方法就是 ViewGroup 和 View 中的相关方法,如下

# View
public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {

    public boolean dispatchTouchEvent(MotionEvent event) {
        // ... 省略部分代码
        boolean result = false;
        // ... 省略部分代码
        if (onFilterTouchEventForSecurity(event)) {
            // ... 省略部分代码
            // 1. 主要调用 onTouchEvent 方法,返回 true 说明事件被消费,否则没被消费
            if (!result && onTouch
首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇FIDE重磅更新!性能飞跃!体验有.. 下一篇Android Studio的安装及环境配置

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目