写的是什么
文章并不是讲解基本的 View 中事件的传递, 而是在我们可以看到的 Android 及 java 中事件的源头是怎么传递出来的。 了解其流程, 有助于更好的理解和学习 Android 的系统。
需要涉及到的类和概念
设计到了 Activity、 PhoneWindow、 WindowManagerImpl、 DecorView、 ViewRootImpl 类及子类或内部类, 需要了解他们的关系及作用。
相关文章:
大致流程总结
从 Activity 的 setContentView 开始
Activity.setContentView 调用到了 window(PhoneWindow).setContentView 。 在 PhoneWindow 中会通过设置的主题等构造出相应主题的 DectorView(一个 Fragment 布局), 该 DectorView 中有一个指定 id content, 即我们 setContentView 的布局父布局, 把我们的布局 add 到 content 布局中即可。
说说 Activity 中的 window
window 在 activity attach 方法中进行赋值, 即看出是 PhoneWindow。 注意在赋值后, window 设置了一个 callback, 其 callback 就是通知各种事件的回调。
界面展示
通过上面的两个整体, 并没有展示出来。 在 ActivityThread 中 handleResumeActivity 可以看到 DectorView 设置了展示, 并 windowManager(WindowManagerImpl) addView 加入了 DectorView。 在 WindowManagerImpl 调用了 WindowManagerGlobal 的 addView, 在这里构造了 ViewRootImpl, 并调用到了 ViewRootImpl 的 setView 把 DectorView 传入。 在 ViewRootImpl 的 setView 中看到, windowSession(WMS) addToDisplay。 addToDisplay 参数中包含了一个 mInputChannel, 这个是一个和 WMS 通信的一个管道(这个并没有过多的研究, 没有看过底层代码, 后面有时间会进行钻读), 看文章等可以了解其通讯并没有使用 Binder, 而是使用了管道和共享内存。 接着会构造一个 WindowInputEventReceiver, 传入了当前的 mInputChannel, 其事件通过其传递出来的进行分发。多提以下, 在 setView 的下面会看到 一些列单链表的结构的 Stage, 这些就是要处理不同事件的类。
事件的传递
WMS 传递 ViewRootImpl, ViewRootImpl 传递给 DectorView, DectorView 传递给 window, window 通过 callback 传递给 Activity, Activity 在交给 window 处理, window 在交给 DectorView 进行传递。 然后就是我们熟悉的在 View 之间的事件传递啦。
源码跟进及验证
setContentView
activity
1 2 3
| public void setContentView(@LayoutRes int layoutResID) { getWindow().setContentView(layoutResID); }
|
PhoneWindow
1 2 3 4 5 6
| public void setContentView(int layoutResID) { if (mContentParent == null) { installDecor(); } mLayoutInflater.inflate(layoutResID, mContentParent); }
|
installDecor 就是构造 DectorView, 其中 mContentParent 为我们设置布局的父布局, 即 DectorView 中 id 为 content 的布局。
installDecor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| private void installDecor() { if (mDecor == null) { mDecor = generateDecor(-1); } if (mContentParent == null) { mContentParent = generateLayout(mDecor); } }
protected DecorView generateDecor(int featureId) { return new DecorView(context, featureId, this, getAttributes()); }
protected ViewGroup generateLayout(DecorView decor) { ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); return contentParent; }
|
window
在 activity 中的 attach:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback) { mWindow = new PhoneWindow(this, window, activityConfigCallback); mWindow.setCallback(this); mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0); }
|
其中 setCallback 设置的接口如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public interface Callback { public boolean dispatchKeyEvent(KeyEvent event); public boolean dispatchKeyShortcutEvent(KeyEvent event); public boolean dispatchTouchEvent(MotionEvent event); public boolean dispatchTrackballEvent(MotionEvent event); public boolean dispatchGenericMotionEvent(MotionEvent event); public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event); public View onCreatePanelView(int featureId); public boolean onCreatePanelMenu(int featureId, Menu menu); public boolean onPreparePanel(int featureId, View view, Menu menu); public boolean onMenuOpened(int featureId, Menu menu); public boolean onMenuItemSelected(int featureId, MenuItem item); public void onWindowAttributesChanged(WindowManager.LayoutParams attrs); public void onContentChanged(); public void onWindowFocusChanged(boolean hasFocus); public void onAttachedToWindow(); public void onDetachedFromWindow(); public void onPanelClosed(int featureId, Menu menu); public boolean onSearchRequested(); public boolean onSearchRequested(SearchEvent searchEvent); public ActionMode onWindowStartingActionMode(ActionMode.Callback callback); public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type); public void onActionModeStarted(ActionMode mode); public void onActionModeFinished(ActionMode mode); default public void onProvideKeyboardShortcuts( List<KeyboardShortcutGroup> data, @Nullable Menu menu, int deviceId) { }; default public void onPointerCaptureChanged(boolean hasCapture) { }; }
|
界面展示及添加 window
在 ActivityThread 的 handleResumeActivity 中:
1 2 3 4 5 6 7 8 9
| public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) { r.window = r.activity.getWindow(); View decor = r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); ViewManager wm = a.getWindowManager(); WindowManager.LayoutParams l = r.window.getAttributes(); wm.addView(decor, l); }
|
其中 wm 即 windowManager 即 WindowManagerImpl, 其中 WindowManagerImpl 的 addView:
1 2 3
| public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); }
|
mGlobal 即 WindowManagerGlobal, 其 addView:
1 2 3 4 5 6 7
| public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { ViewRootImpl root; View panelParentView = null; root = new ViewRootImpl(view.getContext(), display); root.setView(view, wparams, panelParentView); }
|
root 即 ViewRootImpl, 其 setView:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mWinFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper());
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; }
|
其中 mwindowSession 即 WMS, addToDisplay 把 window 进行了添加, 通过上面的分析可知, mInputChannel,是和 WMS 的一个通道, 其事件传递过来后通过 WindowInputEventRceiver 分发出来。
最下面的各种 Stage 即各种各样的事件类型。
事件分发
WindowInputEventReceiver 中 onInputEvent:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public void onInputEvent(InputEvent event, int displayId) { enqueueInputEvent(event, this, 0, true); }
void enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately) { doProcessInputEvents(); }
void doProcessInputEvents() { deliverInputEvent(q); }
private void deliverInputEvent(QueuedInputEvent q) { Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent", q.mEvent.getSequenceNumber()); InputStage stage; stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage; stage.deliver(q); }
|
其中 stage 就是上面 ViewRootImpl setView 中最下面的各种时间类型, 我们看一个即可。
ViewPostImeInputStage 中 onProcess:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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); } } }
|
随便看一个 processs xxx 吧。 processPointerEvent:
1 2 3 4 5
| private int processPointerEvent(QueuedInputEvent q) { final MotionEvent event = (MotionEvent)q.mEvent; boolean handled = mView.dispatchPointerEvent(event); return handled ? FINISH_HANDLED : FORWARD; }
|
mView 即 DectorView, 但 DectorView 并没有实现 dispatchPointerEvent, 在 View 中:
1 2 3 4 5 6 7
| public final boolean dispatchPointerEvent(MotionEvent event) { if (event.isTouchEvent()) { return dispatchTouchEvent(event); } else { return dispatchGenericMotionEvent(event); } }
|
其中 dispatchxxxEvent 就可以在 DectorView 中了, 随便挑一个:
1 2 3 4 5
| public boolean dispatchTouchEvent(MotionEvent ev) { final Window.Callback cb = mWindow.getCallback(); return cb != null && !mWindow.isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev); }
|
mWindow 就是我们的 PhoneWindow 了哈, 然后还记得 window 的 callback 是什么吗? 对, 就是前面初始化 PhoneWindow 时设置的哈。 这这里会对回调做判断, 如果为空的话, 就直接调用 super 的, 其实在 Activity 中回调中最后也是调用到了同样的结果。
通过 callback 回调到 Activity 中, 其中 Activity 的 dispatchTouchEvent:
1 2 3 4 5 6
| public boolean dispatchTouchEvent(MotionEvent ev) { if (getWindow().superDispatchTouchEvent(ev)) { return true; } return onTouchEvent(ev); }
|
getWindow 就是 PhoneWindow 了哈, 然后看看 PhoneWindow 中的 superDispatchTouchEvent:
1 2 3
| public boolean superDispatchTouchEvent(MotionEvent event) { return mDecor.superDispatchTouchEvent(event); }
|
mDecor 即 DectorView, 及 DectorView 的 superDispatchTouchEvent:
1 2 3
| public boolean superDispatchTouchEvent(MotionEvent event) { return super.dispatchTouchEvent(event); }
|
哈哈, 还是这里。 再往后走就到我们比较熟悉的 View 之间的传递啦, 就不再说了。
那么好到这里就分析完毕拉。