序言:很多人都會用Activity槐臀、Window锄蹂、View,但是你知道他們是怎樣加載出來并呈現(xiàn)在你眼前的嗎水慨?你知道他們之間有著鮮為人知的關(guān)系嗎得糜?
講個很簡單的例子,這一天天氣甚好晰洒,小明外出寫生朝抖,小明背了一包東西,畫板啊欢顷,紙啊槽棍,筆啊什么的,然后小明找了一處風(fēng)景甚好的地方抬驴,從包里拿出畫板炼七,紙,筆然后開始畫畫布持,不一會兒小明就畫完了一幅風(fēng)景圖豌拙。在這個例子當(dāng)中,畫板就好比Activity
题暖,紙就好比Window
按傅,而筆就是View
捉超,我們所看到的就是這幅畫,是通過筆一點(diǎn)一點(diǎn)畫出來的唯绍,在哪里畫呢拼岳?當(dāng)然是紙上了,而最終承載這幅畫的東西就是畫板了况芒。這么說可能不太生動惜纸,下面,我們從源碼的角度來看看這三者的關(guān)系绝骚。
Activity的創(chuàng)建過程
我們都知道耐版,Activity啟動的時候是從ActivityThread中的Handler中發(fā)起的,然后經(jīng)過handlerLauncher等一系列方法压汪,如果還不知道的話可以去參考我之前寫的一步一步帶你探索Activity的啟動流程
ActivityThread類:
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
...
WindowManagerGlobal.initialize();
Activity a = performLaunchActivity(r, customIntent);
...
}
在這里先調(diào)用了WindowManagerGlobal
中的初始化方法初始化了WindowManagerService
粪牲,看名字大概就能知道這是一個WindowManager
的服務(wù),通過這個服務(wù)可以對頁面進(jìn)行操作止剖;然后通過調(diào)用performLaunchActivity
方法生成了一個Activity腺阳。
Window的創(chuàng)建過程
上面通過performLaunchActivity
方法生成了一個Activity,我們來看看是怎樣生成的:
ActivityThread類:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
try {
activity = mInstrumentation.newActivity(cl,
component.getClassName(), r.intent);
} catch (Exception e) {
...
}
...
if (activity != null) {
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
}
...
}
在這個方法中滴须,通過newActivity
這個方法(反射)來生成了一個Activity
舌狗,生成好了Activity
之后就調(diào)用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,
Window window, ActivityConfigCallback activityConfigCallback) {
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
}
果然扔水,在Activity
的attach
方法中創(chuàng)建了一個Window
痛侍,這個Window
就是我們經(jīng)常聽到的PhoneWindow
View的創(chuàng)建過程
我們大膽的猜測一下,View
應(yīng)該是被添加到Window
中的魔市,那么我們來看一下主届,到底是怎樣添加的呢?上面說到在handlerLauncher
中調(diào)用了performLaunchActivity
方法待德,源碼中還調(diào)用了handleResumeActivity
方法君丁,這個方法是在生命周期onCreate
之后,onResume
之前調(diào)用的将宪,我們來看一下在這個方法中干了些什么:
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
...
r = performResumeActivity(token, clearHide, reason);
...
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
...
wm.addView(decor, l);
...
}
}
這里會先獲取一個Window
和DecorView
绘闷,然后拿到ViewManager
(WindowManager
的父類),然后調(diào)用addView
方法较坛,ViewManager
和WindowManager
都是接口印蔗,那么我們只要到他的實(shí)現(xiàn)類WindowManagerImpl
中去找addView
方法就可以了:
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
這個mGlobal
就是我們之前的WindowManagerGlobal
,看到這里相信大家應(yīng)該有點(diǎn)眉目了吧丑勤,最終是由這貨負(fù)責(zé)把DecorView
添加到Window中华嘹,在WindowManagerGlobal
中的addView
方法中還會初始化ViewRootImpl
,有興趣的可以自行看源碼了解一下
XML
中的View
是如何添加到DecorView
中的這個也不在這里分析了法竞,可以參考我之前寫的一步一步帶你解析setContentView源碼
總結(jié)
啥也不說了耙厚,上圖