事件分发机制View执行流程学习总结

View->消费事件

我们以Activity中的Button按钮为例,我们点击按钮时有两种情况,一种就是OnTouchListener和OnClickListener,点击按钮时,我们会先执行View.java中的dispatchTouchEvent(MotionEvent event)方法进行事件分发,这个方法里面会进行判断,源码如下:

 public boolean dispatchTouchEvent(MotionEvent event) {
       

        /**
         * 判断touch事件是否安全
         */
        if (onFilterTouchEventForSecurity(event)) {

            ...
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }

第一步:这里的判断条件有四个,一个个看,首先是li != null, mListenerInfo是在Activity的点击监听里面进行赋值的

btnBtn.setOnTouchListener(this);

由按钮实现View.java的setOntouchListener,对mListenerInfo进行了赋值

 public void setOnTouchListener(OnTouchListener l) {
        getListenerInfo().mOnTouchListener = l;
    }

为什么说这里进行了赋值,我们再往深一点看,看到这里,就可以确定只要我们在Activity中设置了点击事件,那么li != null就一定为true

@UnsupportedAppUsage
    ListenerInfo getListenerInfo() {
        if (mListenerInfo != null) {
            return mListenerInfo;
        }
        mListenerInfo = new ListenerInfo();
        return mListenerInfo;
    }

第二步:我们回到第一步里面,还有三个判断条件,现在我们看第二个

 li.mOnTouchListener != null,因为我们在Activity中的设置点击事件时的代码如下

 btnBtn.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.i("jett", "onTouch: ");
                return false;
            }
        });

因为我们new 了一个View.OnTouchListener(),所以li.mOnTouchListener != null为true,

第三步:(mViewFlags & ENABLED_MASK) == ENABLED这个条件的意思是按钮可以点击,enable表示按钮默认可以点击,所以如果是按钮的话,这里条件默认也是true,那么就只剩最后一个条件,前面三个条件恒成立,那么就是最后一个条件影响着result返回值

li.mOnTouchListener.onTouch(this, event)) 

可以看到,这里的话就是一个onTouch(this,event)方法,这个onTouch(this,event)的返回值在Activity回调的时候我们自己设置

 btnBtn.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.i("jett", "onTouch: ");
                return false;
            }
        });

可以看到我们设置的是一个false,所以

if (!result && onTouchEvent(event)) {
                result = true;
            }

result的值直接影响OnTouchEvent(event)的执行,因为我们return false,所以,我们执行onTouchEvent(event),看一下源码,这里面就有

MotionEvent.ACTION_UP、按钮按下
MotionEvent.ACTION_DOWN、按钮抬起
MotionEvent.ACTION_MOVE、按住滑动
MotionEvent.ACTION_CANCEL、取消

点击事件是在

MotionEvent.ACTION_UP这个case里面执行的,所以我们看下源码
switch (action) {
                case MotionEvent.ACTION_UP:
                   ...
                        if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
                            // This is a tap, so remove the longpress check
                            removeLongPressCallback();

                            // Only perform take click actions if we were in the pressed state
                            if (!focusTaken) {
                                // Use a Runnable and post this rather than calling
                                // performClick directly. This lets other visual state
                                // of the view update before click actions start.
                                if (mPerformClick == null) {
                                    mPerformClick = new PerformClick();
                                }
                                if (!post(mPerformClick)) {
                                    performClickInternal();
                                }
                            }
                        }

点击事件在这个new PerformClick();开始进入,到performClickInternal(),返回performClick()

 public boolean performClick() {
        // We still need to call this method to handle the cases where performClick() was called
        // externally, instead of through performClickInternal()
        notifyAutofillManagerOnClick();

        final boolean result;
        final ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnClickListener != null) {
            //点击声音的处理
            playSoundEffect(SoundEffectConstants.CLICK);
            li.mOnClickListener.onClick(this);
            result = true;
        } else {
            result = false;
        }

        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);

        notifyEnterOrExitForAutoFillIfNeeded(true);

        return result;
    }
根据前面所说,li != null 是一定成立的,所以点击事件能否执行,取决于li.mOnClickListener != null,而这个条件又取决于我们是否在Activity中是否设置了点击监听事件。
   btnBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.i("jett", "onClick: ");
            }
        });

然后就是根据这个执行流程,我们可以分析出,

1、OnTouch,OnTouchEvent,OnClick的一个执行顺序是OnTouch -> OnTouchEvent -> OnClick

2、OnTouchEvent不是一定执行的,它能否执行取决于result的值,是为true还是false,也就是取决于OnTouch能否执行,进一步也就是是否设置了点击事件,同时还要判断是否默认为可点击状态enable,如:imageView,它就是默认不可点击的。

以上就是View->消费事件的一个流程的个人学习总结,如有错误,还请大佬多多指正,流程图我是画不出来了=。=,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值