江三沐洛的博客

江三沐洛的博客

安卓OnTouchListener,onTouchEvent,onClickListener执行顺序

安卓控件有很多监听事件,比较典型的有OnTouchListener,onTouchEvent和mOnClickListener,来看下他们的执行顺序
我们先自定义一个Button,在他的onTouchEvent方法中加入log

@Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("xw", "onTouchEvent");
        return super.onTouchEvent(event);
    }

放进布局后在Activity中设置回调

bt1.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e("xw", "OnTouchListener");
                return false;
            }
        });

bt1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("xw", "OnClickListener");
            }
        });

之后单击下,log信息为
这里写图片描述

可见是首先执行OnTouchListener,之后为onTouchEvent,最后才执行onClickListener内的方法,至于为什么OnTouchListener和onTouchEvent执行了两次,是因为在DOWN和UP时两个方法都被调用,至于onClickListener则只在UP的时候调用

我们看下安卓是怎么实现的

与事件分发相关联的三个方法分别为dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent,直接去看View的dispatchTouchEvent方法

public boolean dispatchTouchEvent(MotionEvent event) {
        ......
        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;
        }
        ......
        return result;
    }

我们先看ListenerInfo ,他是View的一个内部静态类

 static class ListenerInfo {

        protected OnFocusChangeListener mOnFocusChangeListener;
        private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;
        protected OnScrollChangeListener mOnScrollChangeListener;
        private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners;
        public OnClickListener mOnClickListener;
        protected OnLongClickListener mOnLongClickListener;
        protected OnContextClickListener mOnContextClickListener;
        protected OnCreateContextMenuListener mOnCreateContextMenuListener;
        ......

    }

里面存储着View的各个Listener,我们之前设置的OnTouchListener也在其中

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

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

其他的像onClickListener也是这样存储

回来我们接着看dispatchTouchEvent方法,从上面我们可以知道如果有的话OnTouchListener是比onTouchEvent先执行的,当然前提是OnTouchListener返回false,即OnTouchListener并没有处理事件

接着调用onTouchEvent方法

public boolean onTouchEvent(MotionEvent event) {
        ......
        switch (action) {
             case MotionEvent.ACTION_UP:
                  ......
                  performClick();
                  ......
                  break;
        ......
    }

public boolean performClick() {
        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);
        return result;
    }

在View的onTouchEvent方法中,如果判断事件为MotionEvent.ACTION_UP时,则会调用performClick,而在performClick中则会回调mOnClickListener的onClick方法,即点击事件被回调,同时直接返回true

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xw13782513621/article/details/76648557
个人分类: 安卓-原理分析
上一篇AMS与Activity的交互
下一篇安卓插件化实例
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭