Android檢視相關之Window.getDecorView()原始碼分析
Window類為抽象類,首先檢視Window類的類註釋
/** * Abstract base class for a top-level window look and behavior policy.An * instance of this class should be used as the top-level view added to the * window manager. It provides standard UI policies such as a background, title * area, default key processing, etc. * * <p>The only existing implementation of this abstract class is * android.view.PhoneWindow, which you should instantiate when needing a * Window. */ public abstract class Window { }
Window類是定義視窗外觀樣式和行為規範的抽象基類,用於作為頂層的View加到WindowManager中;
PhoneWindow是它唯一的實現類。
那麼現在來看一下PhoneWindow
private DecorView mDecor; @Override public final View getDecorView() { if (mDecor == null || mForceDecorInstall) { installDecor(); } return mDecor; } private void installDecor() { mForceDecorInstall = false; if (mDecor == null) { mDecor = generateDecor(-1); ... } else { mDecor.setWindow(this); } if (mContentParent == null) { mContentParent = generateLayout(mDecor); ... } } --> protected DecorView generateDecor(int featureId) { ... return new DecorView(context, featureId, this, getAttributes()); } //DecorView是個FrameLayout public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks { } --> protected ViewGroup generateLayout(DecorView decor) { // Apply data from current theme. TypedArray a = getWindowStyle(); //很長一段都是設定一些Window的屬性或者標誌; ... // Inflate the window decor. //根據設定好的window屬性標誌來選擇layout佈局, 賦值到layoutResource int layoutResource; int features = getLocalFeatures(); // System.out.println("Features: 0x" + Integer.toHexString(features)); if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) { layoutResource = R.layout.screen_swipe_dismiss; } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) { if (mIsFloating) { TypedValue res = new TypedValue(); getContext().getTheme().resolveAttribute( R.attr.dialogTitleIconsDecorLayout, res, true); layoutResource = res.resourceId; } else { layoutResource = R.layout.screen_title_icons; } ... } //還有多個window屬性的判斷,layoutResource賦值 ,和上面這一段基本一樣 ... mDecor.startChanging();//mChanging = true;修改標誌 mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);//重點程式碼,請看下一段 ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); if (contentParent == null) { throw new RuntimeException("Window couldn't find content container view"); } ... mDecor.finishChanging(); return contentParent; }
小結:
1、generateDecor()用於new一個DecorView,賦值給mDecor;
2、generateLayout()設定window的一些屬性,根據屬性獲取對應的layout,然後執行mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
再繼續分析onResourcesLoaded(LayoutInflater inflater, int layoutResource) 方法
//onResourcesLoaded主要是把layoutResource inflate出來,新增到DecorView中 void onResourcesLoaded(LayoutInflater inflater, int layoutResource) { mStackId = getStackId(); //mBackdropFrameRenderer 用於繪製背景的執行緒,不為空時先繪製DecorView的背景 if (mBackdropFrameRenderer != null) { loadBackgroundDrawablesIfNeeded(); mBackdropFrameRenderer.onResourcesLoaded( this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable, mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState), getCurrentColor(mNavigationColorViewState)); } //window的標題View,顯示與否取決於window的型別和作用場景 mDecorCaptionView = createDecorCaptionView(inflater); final View root = inflater.inflate(layoutResource, null);//建立這個layoutResource 的 View 例項物件 root if (mDecorCaptionView != null) { // 先新增 mDecorCaptionView(如果不為null),再向 mDecorCaptionView 中新增 root if (mDecorCaptionView.getParent() == null) { addView(mDecorCaptionView, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); } mDecorCaptionView.addView(root, new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT)); } else { // Put it below the color views. addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); } mContentRoot = (ViewGroup) root; initializeElevation(); }
把layoutResource inflate出來,新增到DecorView中
總結 PhoneWindow.getDecorView()
如果是第一次呼叫mWindow.getDecorView()方法時,mDecor 為空,執行installDecor(),步驟如下:
1、執行generateDecor()方法,new一個DecorView ,賦值到變數mDecor ;
2、執行generateLayout(DecorView decor)方法,把mDecor 傳睇進去;
(2.1)獲取主題設定,配置一些Window的屬性標誌;
(2.2)根據Window的屬性標誌,給layoutResource選擇對應的layout賦值,這些layout的共同點是都包含一個id為@android:id/content的layout;
(2.3)把2.2步驟的layoutResource inflate成view,用addview最終新增到DecorView的中。