-
Activity- 作用:負責(zé)生命周期管理與事件處理,每個
Activity組合了一個Window,實際視圖控制是交由Winodw管理ui排版。是為了滿足多窗口管理和傻瓜式視圖管理的需要而誕生的。 - 起源:在
Activity中的onCreate()方法中會調(diào)用setContentView()加載自定義視圖,實際調(diào)用的是Window的setContentView方法 - 相關(guān)源碼:
android/app/Activity.java public void setContentView(@LayoutRes int layoutResID) { //調(diào)用mWindow.setContentView() getWindow().setContentView(layoutResID); initWindowDecorActionBar(); }android/app/Activity.java final void attach(... ...){ ... ... //實例化mWindow mWindow = new PhoneWindow(this, window, activityConfigCallback); //實現(xiàn)window的接口,鍵盤觸摸 ui策略等 mWindow.setWindowControllerCallback(this); mWindow.setCallback(this); mWindow.setOnWindowDismissedCallback(this); ... ... }
- 作用:負責(zé)生命周期管理與事件處理,每個
-
Window- 作用:唯一實現(xiàn)類
PhoneWindow,創(chuàng)建了頂層視圖DecorView,DecorView作為父布局用來加載Activity中setContentView()方法傳入的layoutRes。是為了管理ui排版,視圖控制而誕生的。 - 相關(guān)源碼:
com/android/internal/policy/PhoneWindow.java @Override public void setContentView(int layoutResID) { if (mContentParent == null) { //創(chuàng)建DecorView,并實例化DecorView布局內(nèi)的ViewGroup控件mContentParent installDecor(); } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); } if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) { final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID, getContext()); transitionTo(newScene); } else { //將mContentParent作為父控件,加載layoutResID mLayoutInflater.inflate(layoutResID, mContentParent); } ... ... }com/android/internal/policy/PhoneWindow.java private void installDecor() { ... ... if (mDecor == null) { //創(chuàng)建DecorView mDecor = generateDecor(-1); ... ... } ... ... if (mContentParent == null) { //實例化mContentParent mContentParent = generateLayout(mDecor); ... ... } }com/android/internal/policy/PhoneWindow.java protected DecorView generateDecor(int featureId) { ... ... //創(chuàng)建DecorView return new DecorView(context, featureId, this, getAttributes()); }com/android/internal/policy/PhoneWindow.java public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content; protected ViewGroup generateLayout(DecorView decor) { ... ... int layoutResource; if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) { layoutResource = R.layout.screen_swipe_dismiss; ... ... } ... ... else { layoutResource = R.layout.screen_simple; } ... ... //加載DecorView布局 mDecor.onResourcesLoaded(mLayoutInflater, layoutResource); //從DecorView中獲取id為content的控件 ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); ... ... //將contentParent返回 return contentParent; }android/view/Window.java public <T extends View> T findViewById(@IdRes int id) { //返回DecorView中給定id的視圖控件 return getDecorView().findViewById(id); }frameworks/base/core/res/res/layout/screen_simple.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" android:orientation="vertical"> <ViewStub android:id="@+id/action_mode_bar_stub" android:inflatedId="@+id/action_mode_bar" android:layout="@layout/action_mode_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="?attr/actionBarTheme" /> <FrameLayout android:id="@android:id/content" android:layout_width="match_parent" android:layout_height="match_parent" android:foregroundInsidePadding="false" android:foregroundGravity="fill_horizontal|top" android:foreground="?android:attr/windowContentOverlay" /> </LinearLayout>
- 作用:唯一實現(xiàn)類
-
DecorView- 作用:繼承自
FrameLayout,是Android視圖樹的根視圖,View層的事件都會先經(jīng)過DecorView,再分發(fā)到下面的View - 相關(guān)源碼:
com/android/internal/policy/DecorView.java void onResourcesLoaded(LayoutInflater inflater, int layoutResource) { mDecorCaptionView = createDecorCaptionView(inflater); //加載PhoneWindow生成的layoutResource final View root = inflater.inflate(layoutResource, null); if (mDecorCaptionView != null) { if (mDecorCaptionView.getParent() == null) { addView(mDecorCaptionView, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); } mDecorCaptionView.addView(root, new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT)); } else { //添加到DecorView中 addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); } mContentRoot = (ViewGroup) root; }
- 作用:繼承自
-
WindowManager- 作用:在
Activity生命周期onResume之后,綁定DecorView與ViewRootImpl。 - 相關(guān)源碼:
android/app/ActivityThread.java public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) { ... ... //執(zhí)行activity的onResume方法 final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); ... ... final Activity a = r.activity; if (r.window == null && !a.mFinished && willBeVisible) { //獲取activity的window實例 r.window = r.activity.getWindow(); //獲取window中實例化的DecorView View decor = r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); //獲取windowManager,獲取的是WindowManager的子類,WindowManagerImpl ViewManager wm = a.getWindowManager(); WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; if (a.mVisibleFromClient) { if (!a.mWindowAdded) { a.mWindowAdded = true; //windowManager調(diào)用addView添加DecorView wm.addView(decor, l); } ... ... } } ... ... }android/view/WindowManagerImpl.java public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); }android/view/WindowManagerGlobal.java public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { ViewRootImpl root; //實例化ViewRootImpl root = new ViewRootImpl(view.getContext(), display); //保存decorView對象 mViews.add(view); //保存viewRootImpl對象 mRoots.add(root); //保存decorView的layout params mParams.add(wparams); try { //綁定ViewRootImpl與DecorView root.setView(view, wparams, panelParentView); }... ... }
- 作用:在
-
ViewRoot(實際實現(xiàn)類是android.view.ViewRootImpl)- 作用
- 連接
DecorView與WindowManager,也可以說是Window與DecorView的紐帶 - 通過
DecorView完成View的三大流程繪制 - 用責(zé)任鏈模式,向
DecorView分發(fā)用戶的InputEvent事件
- 連接
- 注意:在
Activity.onResume()之后,ViewRootImpl.setView中將DecorView傳入,并在之后執(zhí)行requestLayout()通過DecorView遞歸執(zhí)行View的三大流程,所以View的三大流程都是在Activity.onResume之后。 - 相關(guān)源碼:
android/view/ViewRootImpl.java final IWindowSession mWindowSession; public ViewRootImpl(Context context, Display display) { //WindowManagerGlobal獲取IWindowSession mWindowSession = WindowManagerGlobal.getWindowSession(); } public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this) { if (mView == null) { //這個mView就是DecorView,view的三大繪制流程均是通過mView來遞歸的 mView = view; ... ... //view的三大繪制流程 requestLayout(); //創(chuàng)建InputChannel mInputChannel = new InputChannel(); //wms根據(jù)當(dāng)前的window創(chuàng)建了SocketPair用于跨進程通信,并對傳入的mInputChannel進行了注冊 //此后ViewRootImpl中的mInputChannel就指向了正確的InputChannel //client端與server端就能進行雙向通信了 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel, mTempInsets); //創(chuàng)建WindowInputEventReceiver,處理事件分發(fā) mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper()); //組裝InputStage責(zé)任鏈 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; } } }-
View的三大繪制流程入口
android/view/ViewRootImpl.java public void requestLayout() { if (!mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested = true; //這里執(zhí)行view的繪制流程 scheduleTraversals(); } } final class TraversalRunnable implements Runnable { @Override public void run() { doTraversal(); } } final TraversalRunnable mTraversalRunnable = new TraversalRunnable(); void scheduleTraversals() { if (!mTraversalScheduled) { ... ... mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); ... ... } } void doTraversal() { if (mTraversalScheduled) { ... ... performTraversals(); ... ... } } private void performTraversals() { ... ... //measure流程 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); //layout流程 performLayout(lp, mWidth, mHeight); //draw流程 performDraw(); } private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) { try { //執(zhí)行DecorView的mesaure流程 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } } private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight) { final View host = mView; try { //執(zhí)行DecorView的layout流程 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight()); } } private void performDraw() { ... ... try { boolean canUseAsync = draw(fullRedrawNeeded); } ... ... } private boolean draw(boolean fullRedrawNeeded) { ... ... if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty, surfaceInsets)) { return false; } ... ... } private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty, Rect surfaceInsets) { ... ... //執(zhí)行DecorView的draw流程 mView.draw(canvas); ... ... } -
- 作用
-
綜上
- 創(chuàng)建
DecorView的流程:-
Activity在attach時,會創(chuàng)建PhoneWindow實例mWindow; -
Activity在onCreate中調(diào)用setContentView方法時,會間接調(diào)用mWindow.setContentView; -
PhoneWindow在setContentView中會創(chuàng)建DecorView的實例,并將Activity傳入的布局加載到DecorView中id為content的mContentParent中; -
DecorView是android視圖樹的根節(jié)點,最底層的View,在PhoneWindow創(chuàng)建布局時generateLayout會根據(jù)不同類型的主題創(chuàng)建布局,其中會有一個id為content的ViewGroup,Activity中傳入的布局文件就是以content為父布局;
-
- 建立
DecorView與WindowManager的聯(lián)系并最終繪制顯示的流程:-
ActivityThread在調(diào)用handleResumeActivity,會執(zhí)行Activity的onResume方法,隨后,會創(chuàng)建ViewRootImpl的實例,獲取Activity的Window實例,并獲取Window中的DecorView實例,使用WindowManager,將ViewRootImpl與DecorView綁定; -
ViewRootImpl獲取到DecorView的實例后,會持有該引用,并分步調(diào)用mView的measure,layout,draw方法。
-
- 當(dāng)
InputManager監(jiān)控到硬件層面的輸入事件時,會通知ViewRootImpl對輸入事件進行底層分發(fā)(具體細節(jié)查看View的事件分發(fā)機制)- 創(chuàng)建
InputChannel,并通過Binder在SystemServer進程中完成InputChannel的注冊。 - 創(chuàng)建
WindowInputEventReceiver來處理事件分發(fā)。 - 組裝
InputStage責(zé)任鏈,負責(zé)不同InputEvent事件的處理。
- 創(chuàng)建
- 創(chuàng)建
-
其他要點
-
View---getLeft()getTop()getRight()getBottom()返回的是View相對與ViewGroup的左上右下距離 -
MotionEvent---getRawX()getRawY()返回的是觸摸點相對于屏幕的x/y距離getX()getY()返回的是觸摸點相對于自身控件的x/y距離
-
- 系列文章
自定義View——背景知識
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
