andorid中dispatchkeyevent事件傳遞及焦點擷取
DalvikVM[localhost:8601]Thread [<1> main] (Suspended (breakpoint at line 740 in Workspace))Workspace.dispatchKeyEvent(KeyEvent) line: 740FrameLayout(ViewGroup).dispatchKeyEvent(KeyEvent) line: 1246FrameLayout(ViewGroup).dispatchKeyEvent(KeyEvent) line: 1246FrameLayout(ViewGroup).dispatchKeyEvent(KeyEvent) line: 1246LinearLayout(ViewGroup).dispatchKeyEvent(KeyEvent) line: 1246PhoneWindow$DecorView(ViewGroup).dispatchKeyEvent(KeyEvent) line: 1246PhoneWindow$DecorView.superDispatchKeyEvent(KeyEvent) line: 1879PhoneWindow.superDispatchKeyEvent(KeyEvent) line: 1361Launcher(Activity).dispatchKeyEvent(KeyEvent) line: 2324Launcher.dispatchKeyEvent(KeyEvent) line: 6542PhoneWindow$DecorView.dispatchKeyEvent(KeyEvent) line: 1806ViewRootImpl.deliverKeyEventPostIme(KeyEvent, boolean) line: 3327ViewRootImpl.handleFinishedEvent(int, boolean) line: 3300ViewRootImpl.handleMessage(Message) line: 2460ViewRootImpl(Handler).dispatchMessage(Message) line: 99Looper.loop() line: 137ActivityThread.main(String[]) line: 4429Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]Method.invoke(Object, Object...) line: 511ZygoteInit$MethodAndArgsCaller.run() line: 795ZygoteInit.main(String[]) line: 562NativeStart.main(String[]) line: not available [native method]Thread [<10> Binder Thread #2] (Running)Thread [<9> Binder Thread #1] (Running)Daemon Thread [<8> FinalizerWatchdogDaemon] (Running)Daemon Thread [<7> FinalizerDaemon] (Running)Daemon Thread [<6> ReferenceQueueDaemon] (Running)Daemon Thread [<11> java.lang.ProcessManager] (Running)Thread [<12> launcher-loader] (Running)Thread [<13> launcher-loader] (Running)Thread [<15> Timer-1] (Running)Thread [<14> Timer-0] (Running)Thread [<18> SoundPool] (Running)Thread [<19> SoundPoolThread] (Running)Thread [<20> Thread-96] (Running)Thread [<21> DaemonThread] (Running)Thread [<17> SerialHandler] (Running)Daemon Thread [<22> RefQueueWorker@org.apache.http.impl.conn.tsccm.ConnPoolByRoute@4202f9a8] (Running)Thread [<25> Thread-104] (Running)Thread [<26> pool-2-thread-1] (Running)Thread [<28> pool-2-thread-2] (Running)Thread [<29> pool-2-thread-3] (Running)Thread [<30> pool-2-thread-4] (Running)Thread [<31> pool-2-thread-5] (Running)Thread [<32> pool-2-thread-6] (Running)Thread [<33> pool-2-thread-7] (Running)Thread [<34> pool-2-thread-8] (Running)Thread [<35> pool-2-thread-9] (Running)Thread [<36> pool-2-thread-10] (Running)Thread [<16> Binder Thread #3] (Running)Thread [<39> AsyncTask #5] (Running)Thread [<40> AsyncTask #6] (Running)Thread [<42> AsyncTask #8] (Running)Thread [<44> AsyncTask #10] (Running)Thread [<49> AsyncTask #15] (Running)Thread [<27> Thread-149] (Running)
從以上我們可以看到事件是通過頂層view往下傳遞的
再查看viewgroup源碼
public boolean dispatchKeyEvent(KeyEvent event) { if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onKeyEvent(event, 1); } if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) { if (super.dispatchKeyEvent(event)) { return true; } } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) { if (mFocused.dispatchKeyEvent(event)) { return true; } } if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onUnhandledEvent(event, 1); } return false; }
是從focused view往下傳遞事件
可以參考:
Android 中keyEvent的訊息處理
再來按home鍵,從新擷取焦點的處理:
Home鍵2.6_BesTVLauncherInside [Android Application]DalvikVM[localhost:8601]Thread [<1> main] (Suspended (breakpoint at line 50 in TintView$1))TintView$1.onFocusChange(View, boolean) line: 50FocusView(View).onFocusChanged(boolean, int, Rect) line: 3863FocusView(CusFocusView).onFocusChanged(boolean, int, Rect) line: 205FocusView(View).handleFocusGainInternal(int, Rect) line: 3685FocusView(View).requestFocus(int, Rect) line: 5378TintView(ViewGroup).onRequestFocusInDescendants(int, Rect) line: 2154TintView(ViewGroup).requestFocus(int, Rect) line: 2110LinearLayout(ViewGroup).onRequestFocusInDescendants(int, Rect) line: 2154LinearLayout(ViewGroup).requestFocus(int, Rect) line: 2110FrameLayout(ViewGroup).onRequestFocusInDescendants(int, Rect) line: 2154FrameLayout(ViewGroup).requestFocus(int, Rect) line: 2110FrameLayout(ViewGroup).onRequestFocusInDescendants(int, Rect) line: 2154FrameLayout(ViewGroup).requestFocus(int, Rect) line: 2110FrameLayout(ViewGroup).onRequestFocusInDescendants(int, Rect) line: 2154FrameLayout(ViewGroup).requestFocus(int, Rect) line: 2110LinearLayout(ViewGroup).onRequestFocusInDescendants(int, Rect) line: 2154LinearLayout(ViewGroup).requestFocus(int, Rect) line: 2110PhoneWindow$DecorView(ViewGroup).onRequestFocusInDescendants(int, Rect) line: 2154PhoneWindow$DecorView(ViewGroup).requestFocus(int, Rect) line: 2113PhoneWindow$DecorView(View).requestFocus(int) line: 5328ViewRootImpl.clearChildFocus(View) line: 2200PhoneWindow$DecorView(ViewGroup).clearChildFocus(View) line: 669LinearLayout(ViewGroup).clearChildFocus(View) line: 669FrameLayout(ViewGroup).clearChildFocus(View) line: 669FrameLayout(ViewGroup).clearChildFocus(View) line: 669FrameLayout(ViewGroup).clearChildFocus(View) line: 669Workspace(ViewGroup).clearChildFocus(View) line: 669ChildLayout(ViewGroup).clearChildFocus(View) line: 669CellLayout(ViewGroup).clearChildFocus(View) line: 669FrameView(ViewGroup).clearChildFocus(View) line: 669FrameLayout(ViewGroup).clearChildFocus(View) line: 669FocusView(View).clearFocus() line: 3756FrameLayout(ViewGroup).clearFocus() line: 682FrameView(ViewGroup).clearFocus() line: 682CellLayout(ViewGroup).clearFocus() line: 682ChildLayout(ViewGroup).clearFocus() line: 682Workspace.snapToScreen(int, int, boolean) line: 1448Workspace.snapToScreen(int) line: 1422Workspace.scrollFirst() line: 1562Launcher.onNewIntent(Intent) line: 1658Instrumentation.callActivityOnNewIntent(Activity, Intent) line: 1123ActivityThread.deliverNewIntents(ActivityThread$ActivityClientRecord, List) line: 2042ActivityThread.performNewIntents(IBinder, List) line: 2055ActivityThread.handleNewIntent(ActivityThread$NewIntentData) line: 2064ActivityThread.access$1400(ActivityThread, ActivityThread$NewIntentData) line: 123ActivityThread$H.handleMessage(Message) line: 1194ActivityThread$H(Handler).dispatchMessage(Message) line: 99Looper.loop() line: 137ActivityThread.main(String[]) line: 4429Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]Method.invoke(Object, Object...) line: 511ZygoteInit$MethodAndArgsCaller.run() line: 795ZygoteInit.main(String[]) line: 562NativeStart.main(String[]) line: not available [native method]Thread [<10> Binder Thread #2] (Running)Thread [<9> Binder Thread #1] (Running)Daemon Thread [<8> FinalizerWatchdogDaemon] (Running)Daemon Thread [<7> FinalizerDaemon] (Running)Daemon Thread [<6> ReferenceQueueDaemon] (Running)Daemon Thread [<11> java.lang.ProcessManager] (Running)Thread [<12> launcher-loader] (Running)Thread [<13> launcher-loader] (Running)Thread [<15> Timer-1] (Running)Thread [<14> Timer-0] (Running)Thread [<18> SoundPool] (Running)Thread [<19> SoundPoolThread] (Running)Thread [<20> Thread-96] (Running)Thread [<21> DaemonThread] (Running)Thread [<17> SerialHandler] (Running)Daemon Thread [<22> RefQueueWorker@org.apache.http.impl.conn.tsccm.ConnPoolByRoute@4202f9a8] (Running)Thread [<25> Thread-104] (Running)Thread [<26> pool-2-thread-1] (Running)Thread [<28> pool-2-thread-2] (Running)Thread [<29> pool-2-thread-3] (Running)Thread [<30> pool-2-thread-4] (Running)Thread [<31> pool-2-thread-5] (Running)Thread [<32> pool-2-thread-6] (Running)Thread [<33> pool-2-thread-7] (Running)Thread [<34> pool-2-thread-8] (Running)Thread [<35> pool-2-thread-9] (Running)Thread [<36> pool-2-thread-10] (Running)Thread [<16> Binder Thread #3] (Running)Thread [<39> AsyncTask #5] (Running)Thread [<40> AsyncTask #6] (Running)Thread [<42> AsyncTask #8] (Running)Thread [<44> AsyncTask #10] (Running)Thread [<49> AsyncTask #15] (Running)
ChildLayout(ViewGroup).clearFocus() line: 682
Workspace.snapToScreen(int, int, boolean) line: 1448
調用了clearfocus
viewgroup中:
/** * {@inheritDoc} */ @Override public void clearFocus() { super.clearFocus(); // clear any child focus if it exists if (mFocused != null) { mFocused.clearFocus(); } }
view中:
public void clearFocus() { if (DBG) { System.out.println(this + " clearFocus()"); } if ((mPrivateFlags & FOCUSED) != 0) { mPrivateFlags &= ~FOCUSED; if (mParent != null) { mParent.clearChildFocus(this); } onFocusChanged(false, 0, null); refreshDrawableState(); } }
ViewRootImpl.clearChildFocus(View) line: 2200
viewrootimpl中:
public void clearChildFocus(View child) { checkThread(); View oldFocus = mFocusedView; if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Clearing child focus"); mFocusedView = mRealFocusedView = null; if (mView != null && !mView.hasFocus()) { // If a view gets the focus, the listener will be invoked from requestChildFocus() if (!mView.requestFocus(View.FOCUS_FORWARD)) { mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); } } else if (oldFocus != null) { mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); } }
viewgroup中:
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { int index; int increment; int end; int count = mChildrenCount; if ((direction & FOCUS_FORWARD) != 0) { index = 0; increment = 1; end = count; } else { index = count - 1; increment = -1; end = -1; } final View[] children = mChildren; for (int i = index; i != end; i += increment) { View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { if (child.requestFocus(direction, previouslyFocusedRect)) { return true; } } } return false; }
children[i]中的第一個節點最先擷取焦點