Android 中Activity,Window和View之間的關係
我想大多數人,對於這3個東西的概念能區分,但是具體區別在哪卻很難說出來。
我這裡根據我個人的理解來講講我個人對這3個概念的理解。當然這裡設計到通用的事件視窗模型等通用GUI設計,我這裡就不打算講了,純粹從概念上來進行區分。
Activity是Android應用程式的載體,允許使用者在其上建立一個使用者介面,並提供使用者處理事件的API,如onKeyEvent, onTouchEvent等。 並維護應用程式的生命週期(由於android應用程式的執行環境和其他作業系統不同,android的應用程式是執行在框架之內,所以他的應用程式不能噹噹從程式的級別去考慮,而更多是從概念上去考慮。android應用程式是由多個活動堆積而成,而各個活動又有其獨立的生命週期)。Activity本身是個龐大的載體,可以理解成是應用程式的載體,如果木有Activity,android應用將無法執行。也可以理解成android應用程式的入口。Acivity的例項物件由系統維護。系統服務ActivityManager負責維護Activity的例項物件,並根據執行狀態維護其狀態資訊。
但在使用者級別,程式設計師可能根願意理解成為一個介面的載體。但僅僅是個載體,它本身並不負責任何繪製。Activity的內部實現,實際上是聚了一個Window物件。Window是一個抽象類,它的具體是在android_src_home/framework/policies/base/phone/com/android/internal/policy/impl目錄下的PhoneWindow.java。
當我們呼叫Acitivity的 setContentView方法的時候實際上是呼叫的Window物件的setContentView方法,所以我們可以看出Activity中關於介面的繪製實際上全是交給Window物件來做的。繪製類圖的話,可以看出Activity聚合了一個Window物件。
下面是PhoneWindow中的setContentView方法的實現:
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
mContentParent.addView(view, params);
final Callback cb = getCallback();
if (cb != null) {
cb.onContentChanged();
}
}
Window內部首先判斷mContentParent是否為空,然後呼叫installDecor方法(安裝裝飾器),我們看看這個方法如何實現的
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
mDecor.setIsRootNamespace(true);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
if (mTitleView != null) {
if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
View titleContainer = findViewById(com.android.internal.R.id.title_container);
if (titleContainer != null) {
titleContainer.setVisibility(View.GONE);
} else {
mTitleView.setVisibility(View.GONE);
}
if (mContentParent instanceof FrameLayout) {
((FrameLayout)mContentParent).setForeground(null);
}
} else {
mTitleView.setText(mTitle);
}
}
}
}
在該方法中,首先建立一個DecorView,DecorView是一個擴張FrameLayout的類,是所有視窗的根View。我們在Activity中呼叫的setConctentView就是放到DecorView中了。這是我們類圖的聚合關係如下:
Activity--->Window--->DecorView
這是我們得出這3個類之間最直接的一個關係。
我們詳細分析一下,類物件是如何被建立的。
先不考慮Activity的建立(因為 Acitivity的例項由ActivityManager維護,是在另一個程式設計到IPC的通訊,後面會講到),而考慮Window和View的建立。
Activity被建立後,系統會呼叫它的attach方法來將Activity新增到ActivityThread當中。我們找到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,
Object lastNonConfigurationInstance,
HashMap<String,Object> lastNonConfigurationChildInstances,
Configuration config) {
attachBaseContext(context);
mWindow= PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
mUiThread = Thread.currentThread();
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstance = lastNonConfigurationInstance;
mLastNonConfigurationChildInstances = lastNonConfigurationChildInstances;
mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
我們看紅色的程式碼部分,就是建立Window物件的程式碼。感興趣的同學可以跟蹤去看看具體是如何建立的。其實很簡單,其內部實現呼叫了Policy物件的makeNewWindow方法,其方法直接new了一個PhoneWindow物件如下:
public PhoneWindow makeNewWindow(Context context) {
return new PhoneWindow(context);
}
這時我們已經可以把流程串起來,Activity建立後系統會呼叫其attach方法,將其新增到ActivityThread當中,在attach方法中建立了一個window物件。
下面分析View的建立。我們知道Window聚合了DocerView,當使用者呼叫setContentView的時候會把一顆View樹仍給DocerView.View樹是已經建立好的例項物件了,所以我們研究的是DocerView是個什麼東西,它是如何被建立的。
我們回頭看看Window實現裡邊的setContentView方法,我們看上面程式碼的紅色部分setContentView-> installDecor-> generateDecor.
generateDecor直接new了一個DecorView物件:
protected DecorView generateDecor() {
return new DecorView(getContext(), -1);
}
我們可以去看看DecorView的實現,它是PhoneWindow的一個內部類。實現很簡單,它預設會包含一個灰色的標題欄,然後在標題欄下邊會包含一個空白區域用來當使用者呼叫setContentView的時候放置使用者View,並傳遞事件,這裡不做詳細分析,感興趣同學可以自己研究研究。
當DecorView建立好之後再回到Window中的setContentView方法中來,見上面程式碼藍色部分,呼叫
mContentParent.addView(view, params);來將使用者的View樹新增到DecorView中。
到這時為止,我想我們已經很清晰的認識到它們3者之間的關係,並知道其建立流程。
現在總結一下:
Activity在onCreate之前呼叫attach方法,在attach方法中會建立window物件。window物件建立時並木有建立Decor物件物件。使用者在Activity中呼叫setContentView,然後呼叫window的setContentView,這時會檢查DecorView是否存在,如果不存在則建立DecorView物件,然後把使用者自己的View 新增到DecorView中。
相關文章
- Activity、View、Window之間關係的分析View
- Window、WindowManager、View 之間的關係View
- Android 中MVC例項之Activity,Window和ViewAndroidMVCView
- 底層剖析 Window 、Activity、 View 三者關係View
- Window, WindowManager和WindowManagerService之間的關係
- Activity啟動分析(二)--建立Window和ViewView
- FAILGROUP和REDUNDANCY之間的關係關係!AI
- Android在多個Activity之間共享一個ViewAndroidView
- Android自定義View之Window、ViewRootImpl和View的三大流程AndroidView
- View生命週期與Activity生命週期的關係View
- UML中類之間的關係
- tablespace和datafile之間的關係
- QT中類之間的關係圖QT
- android 中Service 和activity之間的資料傳遞的幾種方法Android
- 大話UML中類之間的關係
- CSS系列:CSS中盒子之間的關係CSS
- 類之間的關係
- 黑客和開源革命之間的關係黑客
- flashback與dmt tbs以及trigger,materialized view log之間的關係!ZedView
- Android中Module之間介面呼叫發現不了繼承關係Android繼承
- Android的Task和Activity相關Android
- 專案管理中各系統之間的關係專案管理
- 網站和伺服器之間的關係網站伺服器
- 如何理解Nginx、uWSGI和Flask之間的關係?NginxFlask
- SDK、JDK、JRE 和JVM 之間的關係JDKJVM
- 【java】類之間的關係Java
- 《Activity顯示介面歷險記》—說說View的那些理不清的關係View
- Activity、View、Window的理解一篇文章就夠了View
- View和Activity的生命週期View
- 效能測試中,TPS和RT之間的關係,你知道嗎?
- C#中 Const 、readonly、static 之間的差別和關係C#
- 在Linux中,Unix和Linux之間的關係是什麼?Linux
- 頁面中多個script塊之間的關係
- unix中lun、pv、vg、lv等之間的關係
- 《純技術分析阿里雲OS和Android之間的關係》補充阿里Android
- Web3和元宇宙之間的關係Web元宇宙
- 備份集和備份片之間的關係
- 工具和敏捷軟體開發之間的關係敏捷