Android Touch事件分发过程详解(6)
我们看到,在onTouchEvent函数中就是对ACTION_UP、ACTION_DOWN、ACTION_MOVE等几个事件进行处理,而最重要的就是UP事件了,因为这个里面包含了对用户点击事件的处理,或者是说对于用户而言相对重要一点,因此放在了第一个case中。在ACTION_UP事件中会判断该view是否enable、是否clickable、是否获取到了焦点,然后我们看到会通过post方法将一个PerformClick对象投递给UI线程,如果投递失败则直接调用performClick函数执行点击事件。
/** * Causes the Runnable to be added to the message queue. * The runnable will be run on the user interface thread. * * @param action The Runnable that will be executed. * * @return Returns true if the Runnable was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public boolean post(Runnable action) { Handler handler; if (mAttachInfo != null) { handler = mAttachInfo.mHandler; } else { // Assume that post will succeed later ViewRoot.getRunQueue().post(action); return true; } return handler.post(action); }
我们看看PerformClick类吧。
private final class PerformClick implements Runnable { public void run() { performClick(); } }
可以看到,其内部就是包装了View类中的performClick()方法。再看performClick()方法:
/** * Register a callback to be invoked when this view is clicked. If this view is not * clickable, it becomes clickable. * * @param l The callback that will run * * @see #setClickable(boolean) */ public void setOnClickListener(OnClickListener l) { if (!isClickable()) { setClickable(true); } mOnClickListener = l; } /** * Call this view's OnClickListener, if it is defined. * * @return True there was an assigned OnClickListener that was called, false * otherwise is returned. */ public boolean performClick() { sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); if (mOnClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); mOnClickListener.onClick(this); return true; } return false; }
代码很简单,主要就是调用了mOnClickListener.onClick(this);方法,即执行用户通过setOnClickListener设置进来的点击事件处理Listener。
总结
用户触摸屏幕产生一个触摸消息,系统底层将该消息转发给ViewRoot ( ViewRootImpl ),ViewRoot产生一个DISPATCHE_POINTER的消息,并且在handleMessage中处理该消息,最终会通过deliverPointerEvent(MotionEvent event)来处理该消息。在该函数中会调用mView.dispatchTouchEvent(event)来分发消息,该mView是一个ViewGroup类型,因此是ViewGroup的dispatchTouchEvent(event),在该函数中会遍历所有的child view,找到该事件的触发的左边与每个child view的坐标进行对比,如果触摸的坐标在该child view的范围内,则由该child view进行处理。如果该child view是ViewGroup类型,则继续上一步的查找过程;否则执行View中的dispatchTouchEvent(event)函数。在View的dispatchTouchEvent(event)中首先判断该控件是否enale以及mOnTouchListent是否为空,如果mOnTouchListener不为空则执行mOnTouchListener.onTouch(event)方法,如果该方法返回false则再执行View中的onTouchEvent(event)方法,并且在该方法中执行mOnClickListener.onClick(this, event) ;方法; 如果mOnTouchListener.onTouch(event)返回true则不会执行onTouchEvent方法,因此点击事件也不会被执行。
粗略的流程图如下 :
相信本文所述对大家进一步深入掌握Android程序设计有一定的借鉴价值。