版權(quán)聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議丧裁,轉(zhuǎn)載請附上原文出處鏈接和本聲明。
本文鏈接:http://www.reibang.com/p/fda04a3709ab
http://www.reibang.com/p/76f94c6452c0文章中最后講到了ViewRootImpl的setView函數(shù)調(diào)用语稠,設(shè)置View和窗口關(guān)聯(lián)(通過調(diào)用mWindowSession的addToDisplay)脚草,以及初始化UI draw方面的工作(硬件加速,enableHardwareAcceleration)和初始化接收事件的相關(guān)邏輯披坏。本篇主要講android的應(yīng)用層事件接收和處理的過程态坦。
本篇的切入點是,android的Native層將消息封裝成InputEvent傳送到Java層開始(至于如何形成Native層消息棒拂,并傳送給Java層的伞梯,這不是應(yīng)用開發(fā)所關(guān)心的,不是本篇的重點)帚屉。
事件從ViewRootImpl傳遞到Activity的根視圖DecorView的過程
ViewRootImpl中mWindowSession添加窗口調(diào)用addToDisplay的時候谜诫,addToDisplay函數(shù)有一個參數(shù)是InputChannel對象,它代表著ViewRootImpl和WindowManagerService的事件輸入關(guān)聯(lián)攻旦,WindowManagerService管理的窗口接收到事件之后喻旷,會通知到處于焦點下的窗口的ViewRootImpl的InputChannel。
事件最終到InputEventReceiver對象進行接收和處理WindowInputEventReceiver繼承InputEventReceiver牢屋,InputEventReceiver接收到事件之后調(diào)用onInputEvent且预,由于對象實例是WindowInputEventReceiver對象,所以最終調(diào)用了WindowInputEventReceiver的onInputEvent函數(shù)烙无,onInputEvent函數(shù)里面調(diào)用了enqueueInputEvent
//創(chuàng)建mInputEventReceiver對象代碼片段锋谐,具體參考ViewRootImpl的setView
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}
@Override
public void onInputEvent(InputEvent event) {
enqueueInputEvent(event, this, 0, true);
}
}
WindowInputEventReceiver mInputEventReceiver;
我們來看看enqueueInputEvent的處理過程ViewRootImpl中有兩個成員變量mPendingInputEventHead,mPendingInputEventTail代表輸入事件的隊列的表頭和表尾
QueuedInputEvent mPendingInputEventHead;
QueuedInputEvent mPendingInputEventTail;
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
mPendingInputEventCount += 1;
if (processImmediately) {
doProcessInputEvents();
} else {
scheduleProcessInputEvents();
}
}
可以看到將事件event封裝成QueuedInputEvent對象之后截酷,將QueuedInputEvent事件q插入mPendingInputEventTail最后無論是調(diào)用doProcessInputEvents還是scheduleProcessInputEvents涮拗,最終都是調(diào)用到doProcessInputEvents函數(shù)
doProcessInputEvents為一個while循環(huán),從mPendingInputEventHead表頭逐個瀏覽取出InputEvent,調(diào)用deliverInputEvent進行處理合搅。
void doProcessInputEvents() {
// Deliver all pending input events in the queue.
while (mPendingInputEventHead != null) {
QueuedInputEvent q = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
if (mPendingInputEventHead == null) {
mPendingInputEventTail = null;
}
q.mNext = null;
mPendingInputEventCount -= 1;
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);
long eventTime = q.mEvent.getEventTimeNano();
long oldestEventTime = eventTime;
if (q.mEvent instanceof MotionEvent) {
MotionEvent me = (MotionEvent)q.mEvent;
if (me.getHistorySize() > 0) {
oldestEventTime = me.getHistoricalEventTimeNano(0);
}
}
mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
deliverInputEvent(q);
}
}
那么deliverInputEvent又是如何處理的呢多搀,它比較簡單,直接調(diào)用InputStage對象stage進行處理灾部,而InputStage是在setView中構(gòu)造的康铭,如下:
private void deliverInputEvent(QueuedInputEvent q) {
InputStage stage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (stage != null) {
stage.deliver(q);
} else {
finishInputEvent(q);
}
}
//代碼片段如下:
// Set up the input pipeline.
CharSequence counterSuffix = attrs.getTitle();
mSyntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
"aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
InputStage imeStage = new ImeInputStage(earlyPostImeStage,
"aq:ime:" + counterSuffix);
InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
"aq:native-pre-ime:" + counterSuffix);
mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;
InputState一系列鏈?zhǔn)秸{(diào)用之后最終會調(diào)用到ViewPostImeInputStage對象的onProcess函數(shù)
final class ViewPostImeInputStage extends InputStage {
public ViewPostImeInputStage(InputStage next) {
super(next);
}
@Override
protected int onProcess(QueuedInputEvent q) {
if (q.mEvent instanceof KeyEvent) {
return processKeyEvent(q);
} else {
final int source = q.mEvent.getSource();
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);
}
}
}
}
根據(jù)事件類型,屏幕觸摸事件是SOURCE_CLASS_POINTER類型赌髓,調(diào)用到processPointerEvent,而processPointerEvent中的eventTarget為Activity的DecorView从藤,事件最終傳遞到DecorView的dispatchPointerEvent函數(shù)
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
mAttachInfo.mUnbufferedDispatchRequested = false;
final View eventTarget =
(event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?
mCapturingView : mView;
mAttachInfo.mHandlingPointerEvent = true;
boolean handled = eventTarget.dispatchPointerEvent(event);
maybeUpdatePointerIcon(event);
mAttachInfo.mHandlingPointerEvent = false;
if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
mUnbufferedInputDispatch = true;
if (mConsumeBatchedInputScheduled) {
scheduleConsumeBatchedInputImmediately();
}
}
return handled ? FINISH_HANDLED : FORWARD;
}
DecorView繼承View,dispatchPointerEvent在View中锁蠕,view中調(diào)用的dispatchTouchEvent夷野,由于繼承關(guān)系,所以最終調(diào)用到了DecorView的dispatchTouchEvent荣倾,下面看看DecorView的dispatchTouchEvent
public final boolean dispatchPointerEvent(MotionEvent event) {
if (event.isTouchEvent()) {
return dispatchTouchEvent(event);
} else {
return dispatchGenericMotionEvent(event);
}
}
//DecorView的dispatchTouchEvent
public boolean dispatchTouchEvent(MotionEvent ev) {
final Window.Callback cb = mWindow.getCallback();
return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
DecorView中的mWindow是PhoneWindow實例對象悯搔,所以dispatchTouchEvent中調(diào)用了Window的Callback,而Callback在前文中說過(http://www.reibang.com/p/76f94c6452c0)舌仍,它是Activity的attach中設(shè)置給PhoneWindow的妒貌,所以就調(diào)用到了Activity的dispatchTouchEvent通危,來看看Activity的dispatchTouchEvent
//Activity的dispatchTouchEvent
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
可以看到Activity的dispatchTouchEvent又調(diào)用getWindow()的superDispatchTouchEvent(ev)進行事件傳遞,而getWindow()返回的也是PhoneWindow灌曙,所以又將事件傳遞回了PhoneWindow菊碟,來看看Phonewindow的superDispatchTouchEvent調(diào)用過程。
//PhoneWindow的superDispatchTouchEvent
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
//mDecor的superDispatchTouchEvent
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
PhoneWindow的superDispatchTouchEvent又調(diào)用了DecorView的superDispatchTouchEvent在刺,而DecorView的superDispatchTouchEvent調(diào)用了dispatchTouchEvent逆害,由于DecorView是繼承FrameLayout的,也就是繼承了ViewGroup蚣驼,所以兜了一圈魄幕,終于又將事件傳遞到了Activity的根View即DecorView的dispatchTouchEvent。
下面我們來總結(jié)下事件傳遞的第一步隙姿,即事件從WindowManagerService傳遞到Activity的根視圖DecorView的過程
1:ViewRootImpl通過mInputEventReceiver對象接收到InputEvent事件輸入梅垄,mInputEventReceiver調(diào)用onInputEvent處理事件。
2:mInputEventReceiver是WindowInputEventReceiver對象输玷,同時繼承InputEventReceiver队丝,所以它的onInputEvent事件處理最終調(diào)用到ViewRootImpl的enqueueInputEvent,把事件插入到mPendingInputEventTail表尾中欲鹏,并調(diào)用doProcessInputEvents進行處理事件机久。
3:doProcessInputEvents處理事件最終調(diào)用到了DecorView的dispatchPointerEvent,將事件傳遞到DecorView赔嚎。
4:DecorView調(diào)用PhoneWindow的Callback又將事件傳遞到Activity的dispatchTouchEvent膘盖。
5:Activity的dispatchTouchEvent又返回調(diào)用PhoneWindow的superDispatchTouchEvent將事件傳遞給PhoneWindow,而PhoneWindow最后將事件傳遞到DecorView即Activity的根視圖的dispatchTouchEvent尤误,dispatchTouchEvent之后就是我們熟悉的View樹的遞歸調(diào)用侠畔,將事件傳遞給焦點View,這在后面詳解损晤。
事件從Activity的根視圖DecorView傳遞給子View的過程
要說清楚這個先得說下遞歸和View的繼承問題软棺。比如階乘的遞歸算法
int factorial(int n){
if(n<=1) return 1;
else return factorial(n-1);
}
比如n=5時。遞歸調(diào)用是factorial(5) = 5factorial(4)=54factorial(3)=543factorial(2)=5432factorial(1)尤勋。由于調(diào)用factorial(1)時滿足if(n<=1) return 1喘落。所有factorial(5)=54321。
在來舉一個繼承的例子最冰,有類A和類B瘦棋,類B繼承類A
class A {
public void event(){
log.d("class A event");
}
public void dispatchEvent(){
event();
}
}
class B extends A{
private A[] mChildren;
public void event() {
log.d("class B event");
}
public void dispatchEvent() {
if(mChildren != null) {
for(int i = 0; i < mChildren.length();++i){
mChildren[i].dispatchEvent();
}
event();
}
}
}
比如上面類B的實例b,它的mChildren有3個實例對象暖哨,分別是b1赌朋,b2和a,那么調(diào)用b的成員函數(shù)dispatchEvent。for循環(huán)就會依次遞歸調(diào)用到b1箕慧,b2和a的dispatchEvent服球,即進入到子類的dispatchEvent中,那么依次輸出就是b1的dispatchEvent()-->event() 輸出:class B event颠焦,然后b2也是輸出:class B event,最后到a往枣,a的類型為類A伐庭,dispatchEvent()中最終調(diào)用到自身的event()所以輸出class A event。最后b對象調(diào)用自身event()輸出class B event分冈。
所以輸出依次為:class B event class B event class A event class B event圾另。
上面例子中類A相當(dāng)于類View,類B相當(dāng)于ViewGroup雕沉,如果明白了上述的調(diào)用過程集乔,基本上明白了View的事件的傳遞的百分六七十。實際的ViewGroup中可能還有onInterceptTouchEvent事件攔截坡椒,以及事件有ACTION_DOWN和ACTION_UP扰路,ACTION_MOVE等不同類型引入了mFirstTouchTarget這個鏈表對象處理差異。
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
&& ev.getAction() == MotionEvent.ACTION_DOWN
&& ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
&& isOnScrollbarThumb(ev.getX(), ev.getY())) {
return true;
}
return false;
}
// First touch target in the linked list of touch targets.
private TouchTarget mFirstTouchTarget;
現(xiàn)在直接從ViewGroup的dispatchTouchEvent說起倔叼。dispatchTouchEvent代碼比較長汗唱,截取部分關(guān)鍵代碼說明
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean handled = false;
//安全檢查,認為返回true丈攒,忽略
if (onFilterTouchEventForSecurity(ev)) {
final int action = ev.getAction();
final int actionMasked = action & MotionEvent.ACTION_MASK;
//step1:如果是ACTION_DOWN事件哩罪,表明是一個事件序列的開始,reset狀態(tài)和clear mFirstTouchTarget
// Handle an initial down.
if (actionMasked == MotionEvent.ACTION_DOWN) {
cancelAndClearTouchTargets(ev);
resetTouchState();
}
//step2:檢查是否進行事件攔截
// Check for interception.
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
} else {
intercepted = true;
}
//step3:檢查是否是cancel狀態(tài)巡验,如果為True际插,則不進入
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) {
View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()
? findChildWithAccessibilityFocus() : null;
//step4:檢查是否DOWN類事件,是才進入显设,不是則表示UP或者MOVE類框弛,根據(jù)保存的mFirstTouchTarget進
//行事件傳遞
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);
//step5:注釋寫的很清楚Find a child that can receive the event.
//find的條件就是事件的坐標(biāo)是否在View上和View是否能接收事件
final int childrenCount = mChildrenCount;
if (newTouchTarget == null && childrenCount != 0) {
final float x = ev.getX(actionIndex);
final float y = ev.getY(actionIndex);
// Find a child that can receive the event.
// Scan children from front to back.
final ArrayList<View> preorderedList = buildTouchDispatchChildList();
final boolean customOrder = preorderedList == null
&& isChildrenDrawingOrderEnabled();
final View[] children = mChildren;
for (int i = childrenCount - 1; i >= 0; i--) {
final int childIndex = getAndVerifyPreorderedIndex(
childrenCount, i, customOrder);
final View child = getAndVerifyPreorderedView(
preorderedList, children, childIndex);
// If there is a view that has accessibility focus we want it
// to get the event first and if not handled we will perform a
// normal dispatch. We may do a double iteration but this is
// safer given the timeframe.
if (childWithAccessibilityFocus != null) {
if (childWithAccessibilityFocus != child) {
continue;
}
childWithAccessibilityFocus = null;
i = childrenCount - 1;
}
//find的條件就是事件的坐標(biāo)是否在View上和View是否能接收事件,這樣就避免了逐個dispathch的問題
if (!canViewReceivePointerEvents(child)
|| !isTransformedTouchPointInView(x, y, child, null)) {
ev.setTargetAccessibilityFocus(false);
continue;
}
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);
//step6:傳遞事件到children View敷硅,成功則將View保存在mFirstTouchTarget列表中
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
// Child wants to receive touch within its bounds.
mLastTouchDownTime = ev.getDownTime();
if (preorderedList != null) {
// childIndex points into presorted list, find original index
for (int j = 0; j < childrenCount; j++) {
if (children[childIndex] == mChildren[j]) {
mLastTouchDownIndex = j;
break;
}
}
} else {
mLastTouchDownIndex = childIndex;
}
mLastTouchDownX = ev.getX();
mLastTouchDownY = ev.getY();
newTouchTarget = addTouchTarget(child, idBitsToAssign);
alreadyDispatchedToNewTouchTarget = true;
break;
}
// The accessibility focus didn't handle the event, so clear
// the flag and do a normal dispatch to all children.
ev.setTargetAccessibilityFocus(false);
}
if (preorderedList != null) preorderedList.clear();
}
}
}
//step7:根據(jù)step4到step6的處理結(jié)果功咒。mFirstTouchTarget是否為空,和根據(jù)UP绞蹦,MOVE等事件進行不同的處理
// Dispatch to touch targets.
if (mFirstTouchTarget == null) {
// 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;
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;
}
}
//step8:UP等事件處理重置狀態(tài)力奋,準(zhǔn)備下一次事件序列流程
// 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;
}
上面的注釋step1到step8主要是事件的dispatch過程中的關(guān)鍵處理過程,step1到step3幽七,可以作為一部分解讀景殷。step1中針對DOWN類事件對一些標(biāo)志位和列表作重置處理,step3作一些是否cancel判斷。step2作事件攔截處理猿挚。如果需要攔截直接跳轉(zhuǎn)到step7咐旧。這個時候mFirstTouchTarget == null成立,調(diào)用dispatchTransformedTouchEvent(ev,canceled,null,TouchTarget.ALL_POINTER_IDS);第三個參數(shù)為空表明沒有child。最終調(diào)用父類View的dispatchTouchEvent航揉。最終將事件分發(fā)給自身處理爬凑。這也就是事件攔截的原理過程。
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
View child, int desiredPointerIdBits) {
final boolean handled;
// Perform any necessary transformations and dispatch.
//child == null為空成立調(diào)用父類View的dispatchTouchEvent
if (child == null) {
handled = super.dispatchTouchEvent(transformedEvent);
} else {
final float offsetX = mScrollX - child.mLeft;
final float offsetY = mScrollY - child.mTop;
transformedEvent.offsetLocation(offsetX, offsetY);
if (! child.hasIdentityMatrix()) {
transformedEvent.transform(child.getInverseMatrix());
}
handled = child.dispatchTouchEvent(transformedEvent);
}
// Done.
transformedEvent.recycle();
return handled;
}
View的dispatchTouchEvent
public boolean dispatchTouchEvent(MotionEvent event) {
boolean result = false;
if (onFilterTouchEventForSecurity(event)) {
//noinspection SimplifiableIfStatement
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;
}
可以看到View的dispatchTouchEvent中先會調(diào)用TouchListener設(shè)置的回調(diào)伊约,比方說的Button等的回調(diào)就是這個時候調(diào)用。如果回調(diào)返回true表示將事件消耗掉了孕蝉,就直接返回屡律。如果返回false就調(diào)用自身的onTouchEvent處理事件。
如果step2不攔截降淮,則進入step4到step6超埋,選擇一個或者多個子View作為事件的分發(fā)對象,遞歸調(diào)用dispatchTouchEvent佳鳖。如果子View在dispatchTouchEvent過程中消耗了事件返回true霍殴,則父View也直接返回,不處理事件腋颠。如果子View未處理事件繁成。則父View處理事件。
至此我們明白的一個ViewGroup分發(fā)事件的過程淑玫。1:先查看是否攔截巾腕,a:如果攔截,調(diào)用自身父類的dispatchTouchEvent分發(fā)事件絮蒿,這之中會調(diào)用TouchListener設(shè)置的回調(diào)或者onTouchEvent處理事件尊搬,返回處理result。b:如果不攔截土涝,會選擇事件坐標(biāo)所在的View或者ViewGroup進行事件分發(fā)(可能有多個View佛寿,依次for循環(huán)調(diào)用)。然后遞歸重復(fù)上面的過程但壮。
最后來總結(jié)下Activity的dispatchTouchEvent函數(shù)調(diào)用冀泻,事件的分發(fā)和處理過程
1:Activity的dispatchTouchEvent中調(diào)用getWindow()的superDispatchTouchEvent將事件分發(fā)給PhoneWindow
2:PhoneWindow中調(diào)用成員變量mDecor(DecorView對象)的superDispatchTouchEvent將事件分發(fā)給DecorView
3:DecorView作為Activity的根視圖同時作為一個ViewGroup。調(diào)用dispatchTouchEvent傳遞事件蜡饵。
4:DecorView的dispatchTouchEvent分發(fā)事件弹渔,根據(jù)onInterceptTouchEvent覺得是否攔截事件,攔截自己最終調(diào)用onTouchEvent處理事件溯祸。不攔截根據(jù)選擇事件坐標(biāo)所在View范圍內(nèi)的View分發(fā)事件肢专,子View根據(jù)是否是最終子View遞歸重復(fù)該過程舞肆。處理之后依次向上層返回。上層View根據(jù)處理result博杖,為true繼續(xù)上傳至根布局椿胯。為false調(diào)用OnTouchEvent處理事件,然后返回結(jié)果剃根。
5:DecorView的dispatchTouchEvent最終處理完成哩盲,返回到Activity,Activity根據(jù)處理結(jié)果為true向上返回狈醉,為false調(diào)用自身的onTouchEvent處理事件种冬,然后接著向上返回到ViewRootImpl。