美文网首页
Activity事件分发源码分析

Activity事件分发源码分析

作者: 李die喋 | 来源:发表于2019-10-04 22:55 被阅读0次

    事件分发的基础认知

    事件分发的本质

    将点击事件(MotionEvent)传递到某个具体的View & 处理的整个过程(事件的传递过程 = 分发过程)

    事件的传递对象

    • Activity
    • ViewGroup
    • view

    Android的UI界面由Activity、ViewGroup、View 及其派生类组成

    事件分发过程中的重要方法

    • public boolean dispatchTouchEvent(MotionEvent ev)

    用来进行事件的分发。如果事件能够传递给当前view,此方法一定会被调用,返回结果受当前view的onTouchEvent和下级view的dispatchTouchEvent方法的影响,表示是否消耗当前事件。

    • public boolean onInterceptTouchEvent(MotionEvent event)

    在上述方法内部调用,用来判断是否拦截某个事件,如果当前view拦截了某个事件,那么在同一个事件序列中,此方法不会被再次调用,返回结果表示是否拦截当前事件。

    • public boolean onTouchEvent(MotionEvent event)

    在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一个事件序列中,当前view无法再次接收到事件。

    上述三个方法可以用如下伪代码表示:

    public boolean dispatchTouchEvent(MotionEvent ev){
        boolean consume = false;
        if(onInterceptTouchEvent(ev)){
            consume = onTouchEvent(ev);
        }else{
            consume = onTouchEvent(ev);
        }
        return consume;
    }
    
    事件分发流程图

    事件分发的源码解析

    Activity事件的分发机制

    当一个点击操作发生时,事件最先传递给当前Activity,由Activity的dispatchTouchEvent来进行事件派发,具体的工作是由Activity内部的Window来完成的。

    源码分析

    public boolean dispatchTouchEvent(MotionEvent ev){
    
        //一般事件列开始都是DOWN事件
        if(ev.getAction() == MotionEvent.ACTION_DOWN){
            // -->>分析一
            onUserInteraction();
            //a.该方法为空方法
            //b.当此Activity在栈顶时,触摸屏幕点击home、back、menu键等都会触发此方法
        }
        // -->>分析二
        if(getWindow().superDispatchTouchEvent(ev)){
            return true;
            //事件交给activity所附属的Window进行分发
            //若返回true:整个事件循环结束
            //若返回false:意味事件无人处理,所有view的onTouchEvent都返回了false,Activity的onTouchEvent被调用。
        }
        // -->>分析三
        return onTouchEvent();
    }
    

    (分析一)onUserInteraction

    onUserInteraction

    每当Key,Touch,Trackball事件分发到当前Activity就会被调用。如果你想当你的Activity在运行的时候,能够得知用户正在与你的设备交互,你可以override该方法。此回调和Activity.onUserLeaveHint为了帮助Activities智能的管理状态栏Notification;特别是为了帮助Activities在恰当的时间取消Notification。

    对活动的Activity.onUserLeaveHint回调的所有调用都将伴随对Activity.OnUserInteraction的调用。这可确保您的活动将被告知相关的用户活动,例如拉下通知窗格并触摸其中的项目。

    请注意,将针对开始触摸手势的触摸操作调用此回调,但可能不会针对随后的触摸移动和触摸操作调用此回调。

    Window如何将事件传递给ViewGroup?

    (分析二)getwindow().superDispatchTouchEvent(ev)

    帮助理解

    1.activity.getWindow()

    getWindow()返回Window抽象类,superDispatchTouchEvent()是Window的抽象方法。

    public abstract boolean superDispatchTouchEvent(MotionEvent ev);
    
    2.PhoneWindow.superDispatchTouchEvent()

    Window的实现类是PhoneWindow,在Activity的启动过程中就创建了Window(PolicyManager(Policy)、makeNewWindow)

    public boolean superDispatchTouchEvent(MotionEvent ev){
        returen mDector.superDispatchTouchWindow(ev);
    }
    

    3.DecorView.superDispatchTouchEvent()

    public final class DecorView extends FrameLayout implents RootViewSurfaceTracker{
        private DecorView mDecor;
        
        public final View getDecorView(){
            if(mDecor == null){
                inStallDecor();
            }
            return mDecor;
        }
    }
    

    由此可见,DecorView的父类是FrameLayout,FrameLayout继承ViewGroup。

    public boolean superDispatchTouchEvent(MotionEvent event){
        return super.dispatchTouchEvent(event);
        //调用父类ViewGroup的dispatchTouchEvent()
        //即将事件传递给ViewGroup去处理,详细请看ViewGroup的事件分发机制
    }
    

    (分析三)Activity.onTouchEvent()

    public boolean onTouchEvent(MotionEvent event) {
        //当一个点击事件未被Activity下任何一个View接收/处理时
        //应用场景:处理发生在Window边界外(顶层view--DecorView)的触摸事件
        // ->> 分析四
        if (mWindow.shouldCloseOnTouch(this, event)) {
            finish();
            return true;
        }
        return false;
        //只有点击事件在Window边界外才会返回true,一般情况都返回false
    

    (分析四)mWindow.shouldCloseOnTouch(this, event)

    public boolean shouldCloseOnTouch(Context context, MotionEvent event) {
    // 主要是对于处理边界外点击事件的判断:是否是DOWN事件,event的坐标是否在边界内等
    if (mCloseOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN && isOutOfBounds(context, event) && peekDecorView() != null) {
        return true;
    }
    return false;
    // 返回true:说明事件在边界外,即 消费事件
    // 返回false:未消费(默认)
    }
    

    总结

    Activity的事件分发流程图

    相关文章

      网友评论

          本文标题:Activity事件分发源码分析

          本文链接:https://www.haomeiwen.com/subject/yjzspctx.html