Activity、View、Window之間關係的分析
通常我們所看到的Activity和View最直觀的關係是在onCreate()方法中設定setContentView(LayoutId),為activity設定佈局檔案,這樣view就在介面上顯示出來了。這個方法做的操作如下:
/**
* Set the activity content from a layout resource. The resource will be
* inflated, adding all top-level views to the activity.
*
* @param layoutResID Resource ID to be inflated.
*
* @see #setContentView(android.view.View)
* @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
*/
public void setContentView(@LayoutRes int layoutResID) {
//其實是呼叫了window(PhoneWindow)的setContentView方法
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
public Window getWindow() {
return mWindow;
}
activity的setContentView最終呼叫的是mWindow的setContentView方法。mWindow的初始化是在activity的attach()方法中做的。
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) {
。。。
//這裡進行了初始化,mWindow的物件其實是Window的子類PhoneWindow
mWindow = new PhoneWindow(this);
//此處省略n行程式碼
。。。。
}
到這裡說明了一點,activity的setContentView()是呼叫了PhoneWindow的setContentView().
接著上PhoneWindow的程式碼:
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
//1、初始化DecorView,生成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 {
//2、載入activity自己的佈局
mLayoutInflater.inflate(layoutResID, mContentParent);
}
//省略n行程式碼
。。。。。
}
phoneWindow中的setContentView()方法一共可以分為兩步。第一步:初始化話DectorView 第二步:載入我們自己設定的佈局。到這裡載入activity自己的view就結束了(ps:至於涉及到FrameWork層的東西這裡就不作描述了)。主要來看一下installDecor()的操作。
private void installDecor() {
if (mDecor == null) {
// 生成DecorView,一個繼承了FrameLayout的view
//private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
mDecor = generateDecor();
//省略若干程式碼
}
if (mContentParent == null) {
//為mContentParent 賦值
mContentParent = generateLayout(mDecor);
}
//省略若干程式碼
}
// 生成DecorView
protected DecorView generateDecor() {
return new DecorView(getContext(), -1);
}
這個方法裡面首先生成了一個DecorView(繼承了FrameLayout),然後呼叫了generateLayout(mDecor)為mContentParent 賦值。mContentParent 是做什麼用的呢?還記得當年的夏雨荷嗎?哦 不 是記得phoneWindow中的setContentView()中執行的mLayoutInflater.inflate(layoutResID, mContentParent)程式碼
嗎。沒錯,這個mContentParent就是作為了activity自己的佈局(也就是我們自己寫的佈局)的一個父佈局而存在。
接下來就看一下這個mContentParent到底是誰吧。
protected ViewGroup generateLayout(DecorView decor) {
//依照慣例 依然是省略n行程式碼
。。。。
// Inflate the window decor.
int layoutResource;
int features = getLocalFeatures();
// 根據不同的features來載入不同的佈局
// 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;
}
。。。。。。
} else {
// Embedded, so no decoration is needed.
layoutResource = R.layout.screen_simple;
// System.out.println("Simple!");
}
mDecor.startChanging();
//這裡 根據layoutId(上面根據不同的features 賦值的layoutResource )載入佈局
View in = mLayoutInflater.inflate(layoutResource, null);
//把載入的佈局放入到decorview中
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;
//public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
//查詢id為ID_ANDROID_CONTENT的控制元件
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
。。。。
// 返回id為ID_ANDROID_CONTENT的控制元件
return contentParent;
}
上面的程式碼主要就是完成了載入系統的佈局、把佈局放入到dectorview中、查詢出com.android.internal.R.id.content的控制元件。這個控制元件就是我們自己寫的佈局的父view。
到這裡window、activity、view之間的關係就清楚了。
1、activity的attach方法中執行了window的初始化,window的例項為PhoneWindow。
2、activity的setContentView(ID)方法最終是呼叫的PhoneWindow的setContentView()方法。
3、PhoneWindow在執行setContentView()的過程中生成了一個frameLayout的子類DecorView.並且根據feature的型別載入了一個對應的系統佈局,放入了decorview中。系統佈局中有一個id為com.android.internal.R.id.content的framelayout,這個frameLayout作為一個父佈局載入我們應用中自己定義的xml檔案。
也就是說,我們所有看到的頁面其實都是在window裡面的,activity其實並不直接掌控view而是藉助於window展現的view。下面是時候放出圖了(這張圖就清楚的展現了activity、view、window之間的關係)
相關文章
- Android 中Activity,Window和View之間的關係AndroidView
- Window、WindowManager、View 之間的關係View
- 底層剖析 Window 、Activity、 View 三者關係View
- Window, WindowManager和WindowManagerService之間的關係
- Activity啟動分析(二)--建立Window和ViewView
- Android 中MVC例項之Activity,Window和ViewAndroidMVCView
- View生命週期與Activity生命週期的關係View
- FAILGROUP和REDUNDANCY之間的關係關係!AI
- 類之間的關係
- flashback與dmt tbs以及trigger,materialized view log之間的關係!ZedView
- 【java】類之間的關係Java
- 《Activity顯示介面歷險記》—說說View的那些理不清的關係View
- Activity、View、Window的理解一篇文章就夠了View
- Android在多個Activity之間共享一個ViewAndroidView
- ODS與DW之間的關係
- UML中類之間的關係
- tablespace和datafile之間的關係
- 不同層之間的物件關係物件
- 關於Activity之間傳送資料
- TLS與SSL之間關係TLS
- ps 與 svmon之間關係
- git、github、gitlab之間的關係GithubGitlab
- UML類圖--類之間的關係
- QT中類之間的關係圖QT
- .Net Framework各版本之間的關係Framework
- 類與類之間的基本關係
- activity之間的跳轉
- table/segment/extent/block之間關係BloC
- 思考 TPS 與 RT 之間的關係
- Java設計模式-類之間的關係Java設計模式
- 介面、抽象類、普通類之間的關係抽象
- 如何理解Nginx, WSGI, Flask之間的關係NginxFlask
- 大話UML中類之間的關係
- react、redux、react-redux之間的關係ReactRedux
- PHP-FPM,Nginx,FastCGI 之間的關係PHPNginxAST
- 黑客和開源革命之間的關係黑客
- CSS系列:CSS中盒子之間的關係CSS
- 談Ubuntu與FOSS之間的關係(轉)Ubuntu