事件分发机制(二)—— Activity 的事件分发机制之源码分析

1. Activity 对点击事件的分发过程

点击事件用 MotionEvent 来表示,当一个点击操作发生时,事件最先传递到当前的 Activity,由Activity 的 dispatchTouchEvent 来进行事件的派发,具体的工作是由 Activity 内部的 Window 来完成的。Window会将事件传递给 decor view,decor view一般就是当前界面的底层容器(即 setContentView 所设置的 View 的父容器),通过 Activity.getWindow.getDecorView()可以获得。我们先从 Activity 的 dispatchTouchEvent 开始分析:

 /**
     * Called to process touch screen events.  You can override this to
     * intercept all touch screen events before they are dispatched to the
     * window.  Be sure to call this implementation for touch screen events
     * that should be handled normally.
     *
     * @param ev The touch screen event.
     *
     * @return boolean Return true if this event was consumed.
     */
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

现在分析上边的代码,首先事件交给 Activity 所属的 Window 进行分发,如果返回 true,整个事件循环就结束了,返回 false 意味着没有人处理,所有 View 的 onTouchEvent 都返回了 false,那么 Activity 的 onTouchEvent 会被调用。


接下来看 Window 是如何将事件传递给 ViewGroup 的,通过源码我们知道,Window 是个抽象类,而 Window 的 superDispatchTouchEvent 也是一个抽象方法,因此我们需要找到 Window 的实现类。在 Window 的源码中 有这么一段话

/**
 * Abstract base class for a top-level window look and behavior policy.  An
 * instance of this class should be used as the top-level view added to the
 * window manager. It provides standard UI policies such as a background, title
 * area, default key processing, etc.
 *
 * <p>The only existing implementation of this abstract class is
 * android.view.PhoneWindow, which you should instantiate when needing a
 * Window.
 */

大概意思就是 Window 类可以控制顶级 View 的行为策略和外观,他的唯一实现位于 android.view.PhoneWindow 中,当你要实现这个 Window 的时候,你并不知道他的细节,因为这个类会重构,只有一个工厂可以使用,尽管这看起来有点模糊,不过我们可以看一下 android.view.PhoneWindow 这个类,尽管实例化的时候此类会重构,仅仅是重构而已,功能还是类似的。


由于 Window 的唯一实现是 PhoneWindow,因此接下来看一下 PhoneWindow 是如何处理点击事件的,如下所示

    @Override
    public boolean superDispatchTouchEvent(MotionEvent event) {
        return mDecor.superDispatchTouchEvent(event);
    }
到这里就很清晰了,PhoneWindow 将事件传递给了 DecorView,这个 DecorView 是什么呢?
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks 
    // This is the top-level view of the window, containing the window decor.
    private DecorView mDecor;
    @Override
    public final View getDecorView() {
        if (mDecor == null || mForceDecorInstall) {
            installDecor();
        }
        return mDecor;
    }
我们知道通过 ((ViewGroup)getWindow().getDecorView().findViewById(R.id.button)).getChildAt(0) 可以获取 Activity 所设置的 View,这个 mDecor 显然就是 getWindow().getDecorView() 返回的 View,我们他通过 setContentView 设置的 View 是它的一个子 View,目前事件传递到 DecorView 这里,由于 DecorView 继承自FrameLayout 且是父 View,所以事件最终会传递给 View。从这里开始,事件已经传递给顶级 View 了,即在 Activity 中通过 setContentView 所设置的 View, 另外顶级 View也叫根 View,顶级 View 一般来说都是 ViewGroup。
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值