美文网首页
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