在Activity 的啟動過程中,調用ActivityThread 的handleResumeActivity 方法時,先得到一個與Activity 關聯的PhoneWindow 對象,然後通過PhoneWindow 來獲取DecorView。 PhoneWindow.java DecorView ...
在Activity 的啟動過程中,調用ActivityThread 的handleResumeActivity 方法時,先得到一個與Activity 關聯的PhoneWindow 對象,然後通過PhoneWindow 來獲取DecorView。
PhoneWindow.java
public final View getDecorView() { if (mDecor == null) { installDecor(); } return mDecor; } private void installDecor() { if (mDecor == null) { // 生成DecorView mDecor = generateDecor(); mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); mDecor.setIsRootNamespace(true); } if (mContentParent == null) { // 根據Window 樣式確定DecorView 中的佈局內容,mContentParent 就是DecorView 的第一個子View,也是我們寫的Activity onCreate()中setContentView() 的父View mContentParent = generateLayout(mDecor); final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(R.id.decor_content_parent); } ... }
DecorView 是PhoneWindow 的一個內部類,繼承FrameLayout,generateDecor() 也是像平時我們自定義View 是new 一個DecorView,只不過多了一個featureId 參數,該參數如果是-1,表示這個View 是一個DecorView
protected DecorView generateDecor() { return new DecorView(getContext(), -1); } private final class DecorView extends FrameLayout { public DecorView(Context context, int featureId) { super(context); mFeatureId = featureId; } }
因此,DecorView 中的佈局是怎樣的,主要是由generateLayout(mDecor) 決定的
protected ViewGroup generateLayout(DecorView decor) { // 獲取Window 的樣式 TypedArray a = getWindowStyle(); ... final WindowManager windowService = (WindowManager) getContext().getSysteService(Context.WINDOW_SERVICE); if (windowService != null) { final Display display = windowService.getDefaultDisplay(); ... } final Context context = getContext(); final int targetSdk = context.getApplicationInfo().targetSdkVersion(); ... WindowManager.LayoutParams params = getAttributes(); // Inflate the window decor int layoutResource; int features = getLocalFeatures(); if (){ // 判讀features 中是否包含FEATURE_SWIPE_TO_DISMISS } else if() { // 如果features 包含自定義的Title layoutResource = R.layout.screen_custom_title; } else { // 如果window 屬性沒有任何裝飾(沒有TitleBar,沒有ActionBar 等) layoutResource = R.layout.screen_simple; } mDecor.startChanging(); // 可以看到DecorView 也是通過inflate 載入佈局的,系統framework 預設的佈局資源位於frameworks\base\core\res\res\layout 目錄下 View in = mLayoutInflater.inflate(layoutResource, null); decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); mContentRoot = (ViewGroup) in; ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); if (contentParent == null) { // 拋出異常 } ... mDecor.finishChanging(); return contentParent; }
由此得出,DecorView 是根據不同的window 屬性通過inflate() 方法載入位於frameworks\base\core\res\res\layout 目錄下對應的佈局資源生成的。至於LayoutInflate.inflate() 方法是如何載入佈局文件並解析生成View 的,將在下篇文章中分析。