这节主要是透过源码来分析触摸事件是如何从Activity传递到View中。
当一个点击事件发生时,最先接受到事件的是Activity,由Activity的dispatchTouchEvent方法进行事件分发,该方法源码如下。
/**
* Called to process touch screen events. You can override this to
* intercept all touch screen events before they are dispatched to the
* window. Be sure to call this implementation for touch screen events
* that should be handled normally.
*
* @param ev The touch screen event.
*
* @return boolean Return true if this event was consumed.
*/
public boolean dispatchTouchEvent(MotionEvent ev) {
/*
* 在ACTION_DOWN的时候,调用onUserInteraction方法,
* 这个方法的作用稍后解释
* **/
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
//如果Window的superDispatchTouchEvent返回true,说明事件被消费
//如果返回false,则由Activity自身消费,即调用其onTouchEvent方法
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
onUserInteraction方法我也是在这里第一次见到,读了下其方法说明,发现该方法还是挺有用处的。/**
* Called whenever a key, touch, or trackball event is dispatched to the
* activity. Implement this method if you wish to know that the user has
* interacted with the device in some way while your activity is running.
* This callback and {@link #onUserLeaveHint} are intended to help
* activities manage status bar notifications intelligently; specifically,
* for helping activities determine the proper time to cancel a notfication.
*
* <p>All calls to your activity's {@link #onUserLeaveHint} callback will
* be accompanied by calls to {@link #onUserInteraction}. This
* ensures that your activity will be told of relevant user activity such
* as pulling down the notification pane and touching an item there.
*
* <p>Note that this callback will be invoked for the touch down action
* that begins a touch gesture, but may not be invoked for the touch-moved
* and touch-up actions that follow.
*
* @see #onUserLeaveHint()
*/
public void onUserInteraction() {
}
当有键盘、触摸或者轨迹球事件分发给Activity的时候,你可以知道用户是否正在交互。与其对应的还有一个回调方法onUserLeaveHint,这两个方法可以很好地帮助Activity管理状态栏上的通知,显然也可以帮助Activity在合适的时间取消通知。接着我们看下onUserLeaveHint的代码。
/**
* Called as part of the activity lifecycle when an activity is about to go
* into the background as the result of user choice. For example, when the
* user presses the Home key, {@link #onUserLeaveHint} will be called, but
* when an incoming phone call causes the in-call Activity to be automatically
* brought to the foreground, {@link #onUserLeaveHint} will not be called on
* the activity being interrupted. In cases when it is invoked, this method
* is called right before the activity's {@link #onPause} callback.
*
* <p>This callback and {@link #onUserInteraction} are intended to help
* activities manage status bar notifications intelligently; specifically,
* for helping activities determine the proper time to cancel a notfication.
*
* @see #onUserInteraction()
*/
protected void onUserLeaveHint() {
当某Activity因为用户操作进入后台,那么onUserLeaveHint将被调用并作为activity生命周期的部分。例如当用户按下home键的时候,onUserLeaveHint将被调用,但是当有来电的时候,那么in-call Activity将自动进入前台,这时onUserLeaveHint将不被调用。
接着还是继续分析Activity的dispatchTouchEvent方法,在该方法中调用了抽象类Window的superDispatchTouchEvent方法,作用是将触屏事件继续传递到View层中,其代码如下:
/**
* Used by custom windows, such as Dialog, to pass the touch screen event
* further down the view hierarchy. Application developers should
* not need to implement or call this.
*
*/
public abstract boolean superDispatchTouchEvent(MotionEvent event);
该方法的具体实现是在PhoneWindow类中,其代码如下:
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
这里,我们可以看到其调用了mDecor的superDispatchTouchEvent方法,mDecor是个啥玩意呢?
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
原来mDecor是DecorView,它是Window的顶级View,关于DecorView后续将会有分析,我们需要知道它继承自FrameLayout。DecorView的superDispatchTouchEvent方法代码如下:
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
到这里,就是调用了FrameLayout的dispatchTouchEvent方法。再往下就是正常的View事件传递过程。