View机制深入学习(三) View中的消息传递及InputManagerService

以TouchEvent为主,看一下View和ViewGroup内部是如何处理Input Events的;
一、View中TouchEvent的投递过程
    现在版本的Android中、事件处理者已经不由InputEventReceiver来承担,而是通过多种形式的InputStage来进行分别处理。如:
final class SyntheticInputStage extends InputStage
final class NativePostImeInputStage extends AsyncInputStage
      implements InputQueue.FinishedInputEventCallback
final class ViewPostImeInputStage extends InputStage
1、InputStage:
/** \frameworks\base\core\java\android\view\ViewRootImpl.java **/
abstract class InputStage {
    private final InputStage mNext;
 
    protected static final int FORWARD = 0;
    protected static final int FINISH_HANDLED = 1;
    protected static final int FINISH_NOT_HANDLED = 2;
 
    /**
     * Creates an input stage.
     * @param next The next stage to which events should be forwarded.
     */
    public InputStage(InputStage next) {
        mNext = next;
    }
 
    /**
     * 处理event
     */
    public final void deliver(QueuedInputEvent q) {
    // 有效的event传递给下一stage
        if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
            forward(q);
        } else if (shouldDropInputEvent(q)) { // 应当被drop的Event
            finish(q, false);
        } else {
            apply(q, onProcess(q));
        }
    }
 
    /**
     * 标记该event为finished,并传递给下一个stage
     */
    protected void finish(QueuedInputEvent q, boolean handled) {
        q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
        if (handled) {
            q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
        }
        forward(q);
    }
 
    /**
     * 将event向前传递给下一个stage
     */
    protected void forward(QueuedInputEvent q) {
        onDeliverToNext(q);
    }
 
    /**
     * 根据result code处理对应的event
     * Applies a result code from {@link #onProcess} to the specified event.
     */
    protected void apply(QueuedInputEvent q, int result) {
        if (result == FORWARD) {
            forward(q);
        } else if (result == FINISH_HANDLED) {
            finish(q, true);
        } else if (result == FINISH_NOT_HANDLED) {
            finish(q, false);
        } else {
            throw new IllegalArgumentException("Invalid result: " + result);
        }
    }
 
    /**
     * 一般继承类会Override该函数
     * Called when an event is ready to be processed.
     * @return A result code indicating how the event was handled.
     */
    protected int onProcess(QueuedInputEvent q) {
        return FORWARD;
    }
 
    /**
     * 将event传递给下一stage
     */
    protected void onDeliverToNext(QueuedInputEvent q) {
        if (DEBUG_INPUT_STAGES) {
            Log.v(TAG, "Done with " + getClass().getSimpleName() + ". " + q);
        }
        if (mNext != null) {
            mNext.deliver(q);
        } else {
        // 调用ViewRootImpl的方法
            finishInputEvent(q);
        }
    }
 
    // 判断是否应该丢弃该Event
    protected boolean shouldDropInputEvent(QueuedInputEvent q) {
        if (mView == null || !mAdded) {
            Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent);
            return true;
        } else if ((!mAttachInfo.mHasWindowFocus || mStopped)
                && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
        // 这里是一个focus事件,但当前该window已经不持有input focus,或者已经stopped.
        // 该情况可能是该event来自于previous stage,但与此同时该window失去了焦点或者已经被停止
            if (isTerminalInputEvent(q.mEvent)) {
                // Don't drop terminal input events, however mark them as canceled.
                q.mEvent.cancel();
                Slog.w(TAG, "Cancelling event due to no window focus: " + q.mEvent);
                return false;
            }
 
            // Drop non-terminal input events.
            Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
            return true;
        }
        return false;
    }
 
    void dump(String prefix, PrintWriter writer) {
        if (mNext != null) {
            mNext.dump(prefix, writer);
        }
    }
}
来重点看一下其继承类ViewPostInmInputStage:

2、ViewPostImeInputStage 

1)ViewPostImeInputStage#onProgress:

/** \frameworks\base\core\java\android\view\ViewRootImpl.java **/
@Override
protected int onProcess(QueuedInputEvent q) {
    if (q.mEvent instanceof KeyEvent) { // 如果是按键事件,processKeyEvent进行处理
        return processKeyEvent(q);
    } else {
        // If delivering a new non-key event, make sure the window is
        // now allowed to start updating.
        handleDispatchDoneAnimating();
        final int source = q.mEvent.getSource();
        // 通过source即事件源来分类型进行处理
        if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
            return processPointerEvent(q);
        } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
            return processTrackballEvent(q);
        } else {
            return processGenericMotionEvent(q);
        }
    }
}

    当判断是 SOURCE_CLASS_POINTER类型的事件后,会调用processPointerEvent方法进行处理。

2)ViewPostImeInputStage#processPointEvent:

/** \frameworks\base\core\java\android\view\View.java **/
private int processPointerEvent(QueuedInputEvent q) {
    final MotionEvent event = (MotionEvent)q.mEvent;
 
    mAttachInfo.mUnbufferedDispatchRequested = false;
    // 此时ViewRootImpl会将事件的处理权移交给View树的根节点,调用dispatchPointerEvent函数
    boolean handled = mView.dispatchPointerEvent(event);
    if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
        mUnbufferedInputDispatch = true;
        if (mConsumeBatchedInputScheduled) {
            scheduleConsumeBatchedInputImmediately();
        }
    }
    return handled ? FINISH_HANDLED : FORWARD;
}

    ViewRootImpl负责将Event事件传递进来,并根据source的不同进行分类处理;进而将事件的控制权与处理权移交给View树的根View进行dispatchPointerEvent进行处理。


3)View#dispatchPointerEvent:

/** \frameworks\base\core\java\android\view\View.java **/
public final boolean dispatchPointerEvent(MotionEvent event) {
    // 按照是否是TouchEvent进行分别处理
    if (event.isTouchEvent()) {
        return dispatchTouchEvent(event);
    } else { // 如果不是调用GenericMotionEvent(Generic——一般的)
        return dispatchGenericMotionEvent(event);
    }
}
    对于TouchEvent,显然是会调用dispatchTouchEvent进行处理的:

4)View#dispatchTouchEvent
/** \frameworks\base\core\java\android\view\View.java **/
public boolean dispatchTouchEvent(MotionEvent event) {
    ......
    // 根据安全策略对Touch Event进行过滤
    if (onFilterTouchEventForSecurity(event)) {
        //noinspection SimplifiableIfStatement
    // ListenerInfo中注册了众多的Listener
        ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnTouchListener != null
                && (mViewFlags & ENABLED_MASK) == ENABLED
                && li.mOnTouchListener.onTouch(this, event)) {
        // 可以看到这里会首先调用TouchListener中的onTouch进行事件处理
            result = true;
        }
 
        // 如果TouchListener中的onTouch返回结果为false的话,View中的onTouchEvent才会继续调用
        if (!result && onTouchEvent(event)) {
            result = true;
        }
    }
    ......
    return result;
}
从上面可以看到onTouch与onTouchEvent之间的区别

1>onTouch方法:
onTouch
方法是View OnTouchListener借口中定义的方法。
当一个View绑定了OnTouchLister后,当有touch事件触发时,就会调用onTouch方法。
(当把手放到View上后,onTouch方法被一遍一遍地被调用)

2>onTouchEvent
方法:
onTouchEvent
方法是override Activity的方法。
重新了ActivityonTouchEvent方法后,当屏幕有touch事件时,此方法就会别调用。
(当把手放到Activity上时,onTouchEvent方法就会一遍一遍地被调用)

View 中存在onTouchEvent方法,在定义View的时候重写onTouchEvent可以进行事件处理。


3>touch
事件的传递:
在一个Activity里面放一个TextView的实例tv,并且这个tv的属性设定为 fill_parent
在这种情况下,当手放到屏幕上的时候,首先会是tv响应touch事件,执行onTouch方法。
如果onTouch返回值为true
表示这个

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值