安卓控件有很多监听事件,比较典型的有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