1.前言
Activity并不會(huì)直接與UI交互的,而是通過Window("UI界面的外框")的子類萧锉,如PhoneWindow來交互的溺欧。
為了Window的管理方便暑认,誕生WindowManager,實(shí)現(xiàn)是WindowManagerImpl召衔,WindowManagerImpl直接或間接的存儲(chǔ)DecorView铃诬,ViewRoot,WindowManager;
DecorView,是整個(gè)ViewTree的最頂層View苍凛,它是一個(gè)FrameLayout布局趣席,代表了整個(gè)應(yīng)用的界面,我們setContentView添加的視圖是被mContentParent"包裹"著添加到DecorView 中的。也就是說醇蝴,我們setContentView的View先添加到mContentParent容器宣肚,然后mContentParent又作為DecorView的子View添加到DecorView中。
ViewRoot對(duì)應(yīng)ViewRootImpl類悠栓,它是連接WindowManager和DecorView的紐帶霉涨,View的三大流程均通過ViewRoot來完成。ActivityThread中闸迷,Activity創(chuàng)建#onCreate方法嵌纲,完成DecorView創(chuàng)建動(dòng)作,當(dāng)onCreate()方法執(zhí)行完畢腥沽,后續(xù)ViewRootImpl#setView方法逮走,并把DecorView作為參數(shù)傳遞進(jìn)去,在這個(gè)方法內(nèi)部今阳,會(huì)通過跨進(jìn)程的方式向WMS(WindowManagerService)發(fā)起一個(gè)調(diào)用师溅,從而將DecorView最終添加到Window上茅信。View的繪制流程從ViewRoot的performTraversals方法開始,經(jīng)過measure墓臭、layout和draw三大流程蘸鲸。想要了解以上詳細(xì)內(nèi)容請(qǐng)戳這里
2.Activity窗口接受屏幕觸摸事件的準(zhǔn)備
這里先說明一下Activity對(duì)事件的分發(fā)過程:DecorView -> Activity -> Window -> DecorView
一個(gè)Activity有一個(gè)PhoneWindow窗口,對(duì)應(yīng)一個(gè)頂層ViewParent的實(shí)現(xiàn)類ViewRootImpl,窗口接受屏幕事件的準(zhǔn)備工作是在ViewRootImpl.setView()中進(jìn)行的:
/**
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
....
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
// 這里先去向主線程發(fā)個(gè)消息稍后就去發(fā)起視圖樹的測(cè)量,布局,
// 繪制顯示工作,這樣下面的操作完成后,視圖窗口顯示出來
// 就可以馬上接受各種輸入事件了
requestLayout();
// 一般沒有特別設(shè)置該窗口不能接受輸入事件設(shè)置,這里if==true
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
// 初始化設(shè)置一個(gè)當(dāng)前窗口可以聯(lián)通接受系統(tǒng)輸入事件的的通道
mInputChannel = new InputChannel();
}
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
// 建立當(dāng)前視圖窗口與系統(tǒng)WindowManagerService服務(wù)的關(guān)聯(lián),
//并傳入剛才創(chuàng)建的mInputChannel
// 會(huì)在WindowManagerService服務(wù)進(jìn)程為該APP窗口生成兩個(gè)
//InputQueue,其中一個(gè)會(huì)調(diào)用InputQueue.transferTo()返回到當(dāng)
//前APP進(jìn)程窗口;另外一個(gè)保留在WindowManagerService為當(dāng)
//前APP窗口創(chuàng)建的WindowState中
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);
} catch (RemoteException e) {
...
} finally {
if (restore) {
attrs.restore();
}
}
...
// 很明顯,view是PhoneWindow的內(nèi)部類DecorView對(duì)象,而
//DecorView extends FrameLayout implements RootViewSurfaceTaker
// 所以這里if==ture
if (view instanceof RootViewSurfaceTaker) {
// 創(chuàng)建InputQueue的create和destroy的通知對(duì)象,這里
//DecroView.willYouTakeTheInputQueue()一般為null
mInputQueueCallback =
((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
}
// 從上面知道,一般沒有特別設(shè)置該窗口不能接受輸入事件設(shè)置,這
//里mInputChannel!=null已經(jīng)生成
if (mInputChannel != null) {
// 一般情況DecroView.willYouTakeTheInputQueue()為null,所以這
//里if==false
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
// 創(chuàng)建一個(gè)與當(dāng)前窗口已經(jīng)生成的InputChannel相關(guān)的接受輸入
//事件的處理對(duì)象
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
view.assignParent(this);
mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
if (mAccessibilityManager.isEnabled()) {
mAccessibilityInteractionConnectionManager.ensureConnection();
}
if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
}
// Set up the input pipeline.
// 這里設(shè)置當(dāng)前各種不同類別輸入事件到來時(shí)候按對(duì)應(yīng)類型依次分
//別調(diào)用的處理對(duì)象
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;
mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
}
}
}
從上面看出,在窗口初始化即ViewRootImpl.setView()中,會(huì)建立當(dāng)前視圖窗口體系與系WindowManagerService服務(wù)的關(guān)聯(lián),并在系統(tǒng)WindowManagerService服務(wù)為該窗口生成兩個(gè)InputChannel輸入事件通道,一個(gè)轉(zhuǎn)移到當(dāng)前頂層ViewParent即ViewRootImpl中,并在ViewRootImpl生成一個(gè)與輸入事件通道關(guān)聯(lián)的事件處理WindowInputEventReceiver內(nèi)部類對(duì)象mInputEventReceiver:
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}
// 重寫了父類onInputEvent,調(diào)用enqueueInputEvent實(shí)際處理native層返回的InputEvent輸入事件
@Override
public void onInputEvent(InputEvent event) {
enqueueInputEvent(event, this, 0, true);
}
@Override
public void onBatchedInputEventPending() {
if (mUnbufferedInputDispatch) {
super.onBatchedInputEventPending();
} else {
scheduleConsumeBatchedInput();
}
}
@Override
public void dispose() {
unscheduleConsumeBatchedInput();
super.dispose();
}
}
// 看下WindowInputEventReceiver父類
public abstract class InputEventReceiver {
....
// Called from native code.
@SuppressWarnings("unused")
// 當(dāng)輸入事件到來時(shí)該方法由native層代碼發(fā)起調(diào)用
private void dispatchInputEvent(int seq, InputEvent event) {
mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event);
}
/**
* Called when an input event is received.
* The recipient should process the input event and then call {@link #finishInputEvent}
* to indicate whether the event was handled. No new input events will be received
* until {@link #finishInputEvent} is called.
*
* @param event The input event that was received.
*/
public void onInputEvent(InputEvent event) {
finishInputEvent(event, false);
}
....
}
至此可以看到,一個(gè)屏幕輸入事件返回處理在當(dāng)前視圖窗口WindowInputEventReceiver內(nèi)部類的onInputEvent(InputEvent event)中,隨即調(diào)用了外部類ViewRootImpl.enqueueInputEvent(event, this, 0, true),需要注意的是這里的參數(shù)flags==0
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
adjustInputEventForCompatibility(event);
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 = mPendingInputEventTail;
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
mPendingInputEventCount += 1;
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);
if (processImmediately) {
doProcessInputEvents();
} else {
scheduleProcessInputEvents();
}
}
先是獲取一個(gè)指向當(dāng)前事件的輸入事件隊(duì)列QueuedInputEvent對(duì)象,然后根據(jù)情況賦值ViewRootImpl成員變量mPendingInputEventHead或者追加到mPendingInputEventTail的mNext尾部,隨即調(diào)用doProcessInputEvents()
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);
}
// We are done processing all input events that we can process right now
// so we can clear the pending flag immediately.
if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}
只要mPendingInputEventHead!=null即當(dāng)前待處理事件隊(duì)列還有事件需要去被處理掉,就一直循環(huán)調(diào)用deliverInputEvent()
private void deliverInputEvent(QueuedInputEvent q) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
q.mEvent.getSequenceNumber());
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}
InputStage stage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (stage != null) {
stage.deliver(q);
} else {
finishInputEvent(q);
}
}
這里分別有兩個(gè)判斷,q.shouldSendToSynthesizer()和q.shouldSkipIme(),上面WindowInputEventReceiver拿到native返回的一個(gè)輸入事件對(duì)象時(shí)候,調(diào)用的ViewRootImpl.enqueueInputEvent(event, this, 0, true),標(biāo)記了輸入事件的QueuedInputEvent對(duì)象至此為止falg==0,所以,這里一般情況調(diào)用在setView()中生成的NativePreImeInputStage mFirstInputStage對(duì)象接著去處理.從setView()方法中可知,一共生成了7個(gè)InputStage的子類對(duì)象依次接龍按事件類型對(duì)應(yīng)去處理,入口是NativePreImeInputStage該子類對(duì)象,NativePreImeInputStage的頂層父類當(dāng)然也是InputStage:
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;
}
/**
* Delivers an event to be processed.
*/
public final void deliver(QueuedInputEvent q) {
if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
forward(q);
} else if (shouldDropInputEvent(q)) {
finish(q, false);
} else {
apply(q, onProcess(q));
}
}
/**
* Marks the the input event as finished then forwards it to the next stage.
*/
protected void finish(QueuedInputEvent q, boolean handled) {
q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
if (handled) {
q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
}
forward(q);
}
/**
* Forwards the event to the next stage.
*/
protected void forward(QueuedInputEvent q) {
onDeliverToNext(q);
}
/**
* 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);
}
}
/**
* 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;
}
/**
* Called when an event is being delivered to the next 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 {
finishInputEvent(q);
}
}
....
}
從構(gòu)造就可以看出,每個(gè)生成的InputStage對(duì)象都會(huì)有一個(gè)成員變量mNext指向下一個(gè)處理事件的InputStage對(duì)象;
deliver()方法先判斷該事件對(duì)象是否已經(jīng)處理完成或者需要拋棄掉,都不滿足則調(diào)用onProcess()處理該事件對(duì)象,處理完成后返回處理結(jié)果給apply()方法后續(xù)工作,根據(jù)onProcess()返回處理結(jié)果是否把事件傳遞給其mNext指向的下一個(gè)InputStage去處理;
當(dāng)然具體處理是在子類的onProcess()中實(shí)現(xiàn)的了
final class NativePreImeInputStage extends AsyncInputStage
implements InputQueue.FinishedInputEventCallback {
public NativePreImeInputStage(InputStage next, String traceCounter) {
super(next, traceCounter);
}
@Override
protected int onProcess(QueuedInputEvent q) {
if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
mInputQueue.sendInputEvent(q.mEvent, q, true, this);
return DEFER;
}
return FORWARD;
}
@Override
public void onFinishedInputEvent(Object token, boolean handled) {
QueuedInputEvent q = (QueuedInputEvent)token;
if (handled) {
finish(q, true);
return;
}
forward(q);
}
}
對(duì)于屏幕觸摸事件,這里NativePreImeInputStage的onProcess()返回FORWARD,即交給其mNext即ViewPreImeInputStage去接龍?zhí)幚?/p>
final class ViewPreImeInputStage extends InputStage {
public ViewPreImeInputStage(InputStage next) {
super(next);
}
@Override
protected int onProcess(QueuedInputEvent q) {
if (q.mEvent instanceof KeyEvent) {
return processKeyEvent(q);
}
return FORWARD;
}
private int processKeyEvent(QueuedInputEvent q) {
final KeyEvent event = (KeyEvent)q.mEvent;
if (mView.dispatchKeyEventPreIme(event)) {
return FINISH_HANDLED;
}
return FORWARD;
}
對(duì)于觸摸事件ViewPreImeInputStage.onProcess()同樣返回FORWARD,交給其其mNext即ViewPreImeInputStage去接龍?zhí)幚鞩meInputStage去處理
/**
* Delivers input events to the ime.
* Does not support pointer events.
*/
final class ImeInputStage extends AsyncInputStage
implements InputMethodManager.FinishedInputEventCallback {
public ImeInputStage(InputStage next, String traceCounter) {
super(next, traceCounter);
}
@Override
protected int onProcess(QueuedInputEvent q) {
if (mLastWasImTarget && !isInLocalFocusMode()) {
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
final InputEvent event = q.mEvent;
if (DEBUG_IMF) Log.v(TAG, "Sending input event to IME: " + event);
int result = imm.dispatchInputEvent(event, q, this, mHandler);
if (result == InputMethodManager.DISPATCH_HANDLED) {
return FINISH_HANDLED;
} else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
// The IME could not handle it, so skip along to the next InputStage
return FORWARD;
} else {
return DEFER; // callback will be invoked later
}
}
}
return FORWARD;
}
@Override
public void onFinishedInputEvent(Object token, boolean handled) {
QueuedInputEvent q = (QueuedInputEvent)token;
if (handled) {
finish(q, true);
return;
}
forward(q);
}
}
很明顯這里是處理輸入法事件的,對(duì)于一般觸摸事件同樣返回FORWARD交給其mNext 即EarlyPostImeInputStage去處理,查看EarlyPostImeInputStage源碼可知其對(duì)于觸摸事件onProcess()返回FORWARD交給其mNext 即NativePostImeInputStage去處理,而NativePostImeInputStage.onProcess()同樣返回FORWARD交給其mNext 即ViewPostImeInputStage去處理,看出ViewPostImeInputStage.onProcess():
final class ViewPostImeInputStage extends InputStage {
....
@Override
protected int onProcess(QueuedInputEvent q) {
if (q.mEvent instanceof KeyEvent) {
return processKeyEvent(q);
} else {
// If delivering a new non-key event, make sure the window is
// now allowed to start updating.
handleDispatchWindowAnimationStopped();
final int source = q.mEvent.getSource();
// Whoops here!!
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);
}
}
}
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
mAttachInfo.mUnbufferedDispatchRequested = false;
boolean handled = mView.dispatchPointerEvent(event);
if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
mUnbufferedInputDispatch = true;
if (mConsumeBatchedInputScheduled) {
scheduleConsumeBatchedInputImmediately();
}
}
return handled ? FINISH_HANDLED : FORWARD;
}
....
}
對(duì)于觸摸事件,這里的if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0)為ture,所以調(diào)用processPointerEvent()去處理,在processPointerEvent()中直接調(diào)用mView.dispatchPointerEvent(event),而mView即窗口的頂層視圖DecroView;
至此,終于看到ViewRootImpl對(duì)輸入事件的準(zhǔn)備工作以及經(jīng)過一系列處理把觸摸事件交由頂層視圖DecroView的過程,DecroView和其父類FrameLayout,ViewGroup均沒有重寫此方法,故在View.dispatchPointerEvent()中:
public final boolean dispatchPointerEvent(MotionEvent event) {
if (event.isTouchEvent()) {
return dispatchTouchEvent(event);
} else {
return dispatchGenericMotionEvent(event);
}
}
很明顯,這里調(diào)用了dispatchTouchEvent()去處理,而DecorView重新了該方法:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// 在Activity.attach()中已經(jīng)把自己設(shè)置賦值到DecroView的外部類Window的Callback mCallback成員變量
// 且在PhoneWindow生成DecroView對(duì)象的時(shí)候傳入的mFeatureId=-1
final Callback cb = getCallback();
return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev)
: super.dispatchTouchEvent(ev);
}
所以這里,調(diào)用了Acitivity.dispatchTouchEvent()去處理
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
又讓PhoneWindow.superDispatchTouchEvent()處理:
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
又讓DecroView.superDispatchTouchEvent()處理:
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
DecroView繼承之FrameLayout,FrameLayout繼承之ViewGroup,所以事件終于到了ViewGroup的dispatchTouchEvent()中去處理了!
到這里,事件終于到了ViewGroup.dispatchTouchEvent()了.
剩下的工作就是 GroupView的dispatchTouchEvent去分發(fā)事件了
3. Activity中的dispatchTouchEvent
public boolean dispatchTouchEvent(MotionEvent ev) {
// onUserInteraction默認(rèn)不執(zhí)行任何動(dòng)作。
// 它是提供給客戶的接口窿锉。
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
// 這里會(huì)調(diào)用到ViewGroup的dispatchTouchEvent()酌摇,
// 即會(huì)調(diào)用Activity包含的根視圖的dispatchTouchEvent()。
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
// 如果superDispatchTouchEvent()返回false嗡载,
// 即Activity的根視圖以及根視圖的子視圖都沒有攔截該事件的話窑多,則調(diào)用Activity的onTouchEvent()
return onTouchEvent(ev);
}
這里重點(diǎn)需要了解:Activity在通過dispatchTouchEvent()傳遞觸摸事件的時(shí)候,會(huì)調(diào)用到ViewGroup的dispatchTouchEvent()洼滚。從而實(shí)現(xiàn)埂息,將Activity中的觸摸事件傳遞給它所包含的View或ViewGroup。
如果Activity中的視圖都沒有對(duì)觸摸事件進(jìn)行攔截的話遥巴,則調(diào)用Activity的onTouchEvent()對(duì)觸摸事件進(jìn)行處理千康。
4. Activity中的onTouchEvent
從上面我們了解到
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
如果superDispatchTouchEvent()返回false的話,意味著铲掐,Activity所包含的視圖都沒有攔截或消費(fèi)該觸摸事件拾弃;那么,就會(huì)調(diào)用Activity的onTouchEvent()來處理觸摸事件迹炼。
下面就看看onTouchEvent()的代碼砸彬。
public boolean onTouchEvent(MotionEvent event) {
if (mWindow.shouldCloseOnTouch(this, event)) {
finish();
return true;
}
return false;
}
代碼很簡(jiǎn)單。它會(huì)先調(diào)用mWindow.shouldCloseOnTouch()斯入,如果shouldCloseOnTouch()返回true砂碉,則意味著該觸摸事件會(huì)觸發(fā)"結(jié)束Activity"的動(dòng)作。那么接下來刻两,就調(diào)用finish()來結(jié)束Activity增蹭,并返回true,表示Activity消費(fèi)了這個(gè)觸摸事件磅摹。否則的話滋迈,就返回false。
我們知道m(xù)Window是PhoneWindow對(duì)象户誓,而PhoneWindow繼承于Window饼灿。則mWindow.shouldCloseOnTouch()實(shí)際上會(huì)調(diào)用Window中的shouldCloseOnTouch()。
public boolean shouldCloseOnTouch(Context context, MotionEvent event) {
if (mCloseOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN
&& isOutOfBounds(context, event) && peekDecorView() != null) {
return true;
}
return false;
}
說明mCloseOnTouchOutside是一個(gè)boolean變量帝美,它是由Window的android:windowCloseOnTouchOutside屬性值決定碍彭。
isOutOfBounds(context, event)是判斷該event的坐標(biāo)是否在context(對(duì)于本文來說就是當(dāng)前的Activity)之外。是的話,返回true庇忌;否則舞箍,返回false。
peekDecorView()則是返回PhoneWindow的mDecor皆疹。
也就是說疏橄,如果設(shè)置了android:windowCloseOnTouchOutside屬性為true,并且當(dāng)前事件是ACTION_DOWN略就,而且點(diǎn)擊發(fā)生在Activity之外捎迫,同時(shí)Activity還包含視圖的話,則返回true残制;表示該點(diǎn)擊事件會(huì)導(dǎo)致Activity的結(jié)束立砸。
總結(jié)
ViewRootImpl對(duì)輸入事件的準(zhǔn)備工作以及經(jīng)過一系列處理把觸摸事件交由頂層視圖DecorView掖疮。DecorView通過重寫dispatchPointerEvent方法初茶,將事件傳遞給Activity。Activity通過dispatchTouchEvent調(diào)用到Activity所屬Window的superDispatchTouchEvent浊闪,進(jìn)而調(diào)用到Window的DecorView的superDispatchTouchEvent恼布,進(jìn)一步的又調(diào)用到ViewGroup的dispatchTouchEvent()。
如果Activity所包含的視圖攔截或者消費(fèi)了該觸摸事件的話搁宾,就不會(huì)再執(zhí)行Activity的onTouchEvent()折汞;
如果Activity所包含的視圖沒有攔截或者消費(fèi)該觸摸事件的話,則會(huì)執(zhí)行Activity的onTouchEvent()盖腿。
Activity中的onTouchEvent是Activity自身對(duì)觸摸事件的處理爽待。如果該Activity的android:windowCloseOnTouchOutside屬性為true,并且當(dāng)前觸摸事件是ACTION_DOWN翩腐,而且該觸摸事件的坐標(biāo)在Activity之外鸟款,同時(shí)Activity還包含了視圖的話;就會(huì)導(dǎo)致Activity被結(jié)束茂卦。