在ViewRootImpl的setView方法中,用戶的觸摸按鍵消息是體現在窗體上的,而windowManagerService則是管理這些窗口,它一旦接收到用戶對窗體的一些觸摸按鍵消息,會進行相應的動作,這種動作是需要體現在具體的view上面,在Android中,一個具體的界面是由一個Activity呈現的,而Activity中則包含了一個window,此window中又包含了一個phoneWindow,這個phoneWindow纔是真正意義上的窗口,它把一個框架佈局進行了一定的包裝,並提供了具體的窗口操作接口,phoneWindow中包含了一個DecorView,這個view纔是包含整個Activity的ui,它將被attach到Activity主窗口中。所以說用戶觸摸按鍵的消息是由windowManagerService捕捉到然後交給phoneWindow中的DecorView進行相應的處理,而連接兩者的橋樑則是一個ViewRoot類,ViewRoot類由windowManagerService創建,其內部有一個W類,這個W類是一個binder,負責WindowManagerService的ipc調用,W接收到windowManagerService發送過來的消息後,把消息傳遞給ViewRoot,進而傳遞給ActivityThread解析做出處理,
1、在ViewRootImpl.java類的setView方法中:
<span style="font-size:14px;"><span style="white-space:pre"> </span>res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),mAttachInfo.mContentInsets, mInputChannel);</span>
在這裏把mWindow傳遞給了window,這個mWindow就是W類的一個實例<span style="font-size:14px;"><span style="white-space:pre"> </span>public void onInputEvent(InputEvent event) {
<span style="white-space:pre"> </span> enqueueInputEvent(event, this, 0, true);
<span style="white-space:pre"> </span>}</span>
<span style="font-size:14px;">void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
// Always enqueue the input event in order, regardless of its time stamp.
// We do this because the application or the IME may inject key events
// in response to touch events and we want to ensure that the injected keys
// are processed in the order they were received and we cannot trust that
// the time stamp of injected events are monotonic.
QueuedInputEvent last = mFirstPendingInputEvent;
if (last == null) {
mFirstPendingInputEvent = q;
} else {
while (last.mNext != null) {
last = last.mNext;
}
last.mNext = q;
}
if (processImmediately) {
// 立即處理事件
doProcessInputEvents();
} else {
// 將事件放到隊列的最後
scheduleProcessInputEvents();
}
}</span>
<span style="font-size:14px;"> private void deliverInputEvent(QueuedInputEvent q) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent");
try {
if (q.mEvent instanceof KeyEvent) {
// 如果是按鍵事件,也就是back、home等按鍵
deliverKeyEvent(q);
} else {
// touch事件
final int source = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
deliverPointerEvent(q);
} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
deliverTrackballEvent(q);
} else {
deliverGenericMotionEvent(q);
}
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}</span>
在deliverPointerEvent方法中,如果view對象不存在,或者沒有被添加,則這個event不會被處理,直接finishInputEvent。接着判斷action是否是MotionEvent.ACTION_DOWN,如果是,則表示觸摸方式改變了,需要告訴windowManager在本地進行處理,因爲每一次的按下操作都代表了一個新的event事件的到來。然後記錄觸摸的位置,這個位置就代表了應該是哪一個view來接收這個事件,然後直接調用mView.dispatchPointerEvent(event)來分發這個事件,如果這個事件被分發下去了,則結束事件。<span style="font-size:14px;"> private void deliverPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
final boolean isTouchEvent = event.isTouchEvent();
if (mInputEventConsistencyVerifier != null) {
if (isTouchEvent) {
mInputEventConsistencyVerifier.onTouchEvent(event, 0);
} else {
mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
}
}
// If there is no view, then the event will not be handled.
if (mView == null || !mAdded) {
// view對象爲空,或者沒有被添加,這個事件就不會被處理
finishInputEvent(q, false);
return;
}
// Translate the pointer event for compatibility, if needed.
if (mTranslator != null) {
mTranslator.translateEventInScreenToAppWindow(event);
}
// Enter touch mode on down or scroll.
final int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
// 如果是MotionEvent.ACTION_DOWN
// 如果是如果觸摸方式改變,告訴wm,在本地進行處理
// 每一次的按下操作就是一個觸摸事件的改變
ensureTouchMode(true);
}
// Offset the scroll position.
if (mCurScrollY != 0) {
event.offsetLocation(0, mCurScrollY);
}
if (MEASURE_LATENCY) {
lt.sample("A Dispatching PointerEvents", System.nanoTime() - event.getEventTimeNano());
}
// Remember the touch position for possible drag-initiation.
// 有可能拖拽開始,記錄觸摸的位置
if (isTouchEvent) {
mLastTouchPoint.x = event.getRawX();
mLastTouchPoint.y = event.getRawY();
}
// Dispatch touch to view hierarchy.
// 給view的層級上view分發事件
// DecorView繼承FrameLayout也就間接繼承了ViewGroup,View
// DoverView---->Activity-->PhoneWindow--->DocerView---->ViewGroup
boolean handled = mView.dispatchPointerEvent(event);
if (MEASURE_LATENCY) {
lt.sample("B Dispatched PointerEvents ", System.nanoTime() - event.getEventTimeNano());
}
if (handled) {
// 結束事件
finishInputEvent(q, true);
return;
}
// Pointer event was unhandled.
// 暗示事件已經被處理
finishInputEvent(q, false);
</span>
在DecorView中沒有dispatchPointerEvent方法,所以調用的是View.java的dispatchPointerEvent方法中判斷具體的是哪一類的事件,然後又調用了自身的dispatchTouchEvent。<span style="font-size:14px;">public final boolean dispatchPointerEvent(MotionEvent event) {
if (event.isTouchEvent()) {
// 如果是觸摸事件
return dispatchTouchEvent(event);
} else {
// 如果是一般的移動事件
return dispatchGenericMotionEvent(event);
}
}</span>
<span style="white-space:pre"> </span>@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// callback就是Activity本身
final Callback cb = getCallback();
// 如果Activity不爲空,並且沒有被銷燬,則調用Activity的dispatchTouchEvent
// 否則調用父類的dispatchTouchEvent
return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev)
: super.dispatchTouchEvent(ev);
}
在Activity的dispatchTouchEvent方法中,調用的是PhoneWindow的superDispatchTouchEvent的方法去分發事件,如果到最後Activity中的所有的view都不去處理這個事件時,就有Activity的OnTouchEvent來處理。public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
// 在dispatch之前做一些操作,其實什麼也沒做
onUserInteraction();
}
// 調用PhoneWindow中的superDispatchTouchEvent
// PhoneWindow中superDispatchTouchEvent 直接調用了mDecor的superDispatchTouchEvent
// mDecore的superDispatchTouchEvent方法中直接調用super.dispatchOnTouchEvent
// 也就是開始進入了viewGroup中的dispatchOnTouchEvent方法
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
// 當Activity中所有的View都不處理Event的時候,就用由Activity的onTouchEvent()來處理
// 通知window關閉這個touch事件
return onTouchEvent(ev);
}
public boolean onTouchEvent(MotionEvent event) {
if (mWindow.shouldCloseOnTouch(this, event)) {
finish();
return true;
}
return false;
}
在PhoneWindow的superDispatchTouchEvent中,調用了DecorView的superDispatchTouchEvent方法,進而調用了super.dispatchTouchEvent(event)方法,也就是進入了viewGroup中開始事件的分發。 @Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
ViewGroup的dispatchTouchEvent中,處理如下,如果action是MotionEvent.ACTION_DOWN,則需要重置觸摸的狀態。繼而判斷是否攔截此事件,然後遍歷所有的孩子以便找到一個可以接收此事件的孩子,如果child不存在TouchTarget中,則把事件分發給子view,這個尋找是根據view的區域來尋找的。如果childView沒有消費掉此事件,則
自己處理的事件,如果自己也沒有處理,回溯至父view處理,否則viewGroup把事件一級一級的遞歸傳遞,如果child是一個viewGroup,則重複上述的步驟,如果是view,直接調用dispatchTouchEvent方法。 public boolean dispatchTouchEvent(MotionEvent ev) {
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
}
boolean handled = false;
if (onFilterTouchEventForSecurity(ev)) {
final int action = ev.getAction();
final int actionMasked = action & MotionEvent.ACTION_MASK;
// Handle an initial down.
if (actionMasked == MotionEvent.ACTION_DOWN) {
// Throw away all previous state when starting a new touch gesture.
// The framework may have dropped the up or cancel event for the previous gesture
// due to an app switch, ANR, or some other state change.
// ACTION_DOWN意味着touch事件的改變,所以需要把之前的TouchTargets和TouchState都clear掉,mFirstTouchTarget = null
cancelAndClearTouchTargets(ev);
// 重置觸摸的狀態
resetTouchState();
}
// Check for interception.
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
// 攔截事件,默認返回false,表示不攔截,如果攔截了就不繼續往下面執行了
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
} else {
// There are no touch targets and this action is not an initial down
// so this view group continues to intercept touches.
intercepted = true;
}
// Check for cancelation.
final boolean canceled = resetCancelNextUpFlag(this)
|| actionMasked == MotionEvent.ACTION_CANCEL;
// Update list of touch targets for pointer down, if needed.
final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
TouchTarget newTouchTarget = null;
boolean alreadyDispatchedToNewTouchTarget = false;
if (!canceled && !intercepted) {
if (actionMasked == MotionEvent.ACTION_DOWN
|| (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
final int actionIndex = ev.getActionIndex(); // always 0 for down
final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
: TouchTarget.ALL_POINTER_IDS;
// Clean up earlier touch targets for this pointer id in case they
// have become out of sync.
removePointersFromTouchTargets(idBitsToAssign);
final int childrenCount = mChildrenCount;
if (childrenCount != 0) {
// Find a child that can receive the event.
// Scan children from front to back.
// 遍歷所有的孩子,以便找到一個可以接收這個事件的孩子
// 某個區域內的孩子
final View[] children = mChildren;
final float x = ev.getX(actionIndex);
final float y = ev.getY(actionIndex);
final boolean customOrder = isChildrenDrawingOrderEnabled();
for (int i = childrenCount - 1; i >= 0; i--) {
final int childIndex = customOrder ?
getChildDrawingOrder(childrenCount, i) : i;
final View child = children[childIndex];
if (!canViewReceivePointerEvents(child)
|| !isTransformedTouchPointInView(x, y, child, null)) {
continue;
}
// 判斷child是否在TouchTarget中
newTouchTarget = getTouchTarget(child);
if (newTouchTarget != null) {
// 存在
// Child is already receiving touch within its bounds.
// Give it the new pointer in addition to the ones it is handling.
newTouchTarget.pointerIdBits |= idBitsToAssign;
break;
}
resetCancelNextUpFlag(child);
// child不存在TouchTarget中,則調用dispatchTransformedTouchEvent
// 把event分發給子view,這裏並不是做處理,應該就是找到touch區域
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
// Child wants to receive touch within its bounds.
mLastTouchDownTime = ev.getDownTime();
mLastTouchDownIndex = childIndex;
mLastTouchDownX = ev.getX();
mLastTouchDownY = ev.getY();
newTouchTarget = addTouchTarget(child, idBitsToAssign);
alreadyDispatchedToNewTouchTarget = true;
break;
}
}
}
if (newTouchTarget == null && mFirstTouchTarget != null) {
// Did not find a child to receive the event.
// Assign the pointer to the least recently added target.
newTouchTarget = mFirstTouchTarget;
while (newTouchTarget.next != null) {
newTouchTarget = newTouchTarget.next;
}
newTouchTarget.pointerIdBits |= idBitsToAssign;
}
}
}
// Dispatch to touch targets.
if (mFirstTouchTarget == null) {
// mFirstTouchTarget 爲空,表示childview沒有將此事件消費掉,則自己處理這個event
// 如果viewGroup自己也沒有處理,則回溯到父view進行處理
// No touch targets so treat this as an ordinary view.
handled = dispatchTransformedTouchEvent(ev, canceled, null,
TouchTarget.ALL_POINTER_IDS);
} else {
// Dispatch to touch targets, excluding the new touch target if we already
// dispatched to it. Cancel touch targets if necessary.
TouchTarget predecessor = null;
TouchTarget target = mFirstTouchTarget;
while (target != null) {
final TouchTarget next = target.next;
if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
handled = true;
} else {
final boolean cancelChild = resetCancelNextUpFlag(target.child)
|| intercepted;
// viewGroup把事件遞歸傳遞,如果child是一個gourp,則重複上述步驟
// 如果是view,則直接調用dispatchTouchEvent方法
if (dispatchTransformedTouchEvent(ev, cancelChild,
target.child, target.pointerIdBits)) {
handled = true;
}
if (cancelChild) {
if (predecessor == null) {
mFirstTouchTarget = next;
} else {
predecessor.next = next;
}
target.recycle();
target = next;
continue;
}
}
predecessor = target;
target = next;
}
}
// Update list of touch targets for pointer up or cancel, if needed.
if (canceled
|| actionMasked == MotionEvent.ACTION_UP
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
resetTouchState();
} else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
final int actionIndex = ev.getActionIndex();
final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
removePointersFromTouchTargets(idBitsToRemove);
}
}
if (!handled && mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
}
return handled;
}
public boolean dispatchTouchEvent(MotionEvent event) {
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTouchEvent(event, 0);
}
if (onFilterTouchEventForSecurity(event)) {
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
// 要想執行onTouchEvent方法上述三個條件只要一個不滿足就可以了
//
return true;
}
if (onTouchEvent(event)) {
return true;
}
// 如果所有的View都不處理TouchEvent,最後由Activity來處理
}
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
}
return false;
}
public boolean onTouchEvent(MotionEvent event) {
if (mWindow.shouldCloseOnTouch(this, event)) {
finish();
return true;
}
return false;
}