從源碼的角度淺談Activity、Window、View之間的關係

序言

很多人都會用Activity、Window、View,但是你知道他們是怎樣加載出來並呈現在你眼前的嗎?你知道他們之間有着鮮爲人知的關係嗎?

講個很簡單的例子,這一天天氣甚好,小明外出寫生,小明背了一包東西,畫板啊,紙啊,筆啊什麼的,然後小明找了一處風景甚好的地方,從包裏拿出畫板,紙,筆然後開始畫畫,不一會兒小明就畫完了一幅風景圖。在這個例子當中,畫板就好比Activity,紙就好比Window,而筆就是View,我們所看到的就是這幅畫,是通過筆一點一點畫出來的,在哪裏畫呢?當然是紙上了,而最終承載這幅畫的東西就是畫板了。這麼說可能不太生動,下面,我們從源碼的角度來看看這三者的關係。

Activity的創建過程

我們都知道,Activity啓動的時候是從ActivityThread中的Handler中發起的,然後經過handlerLauncher等一系列方法,如果還不知道的話可以去參考我之前寫的:https://github.com/24Kshign/Android-Knowledge/blob/a8b38bf4765df13fee3a573249a1dc472f3a7e6c/Android%E6%BA%90%E7%A0%81%E7%9B%B8%E5%85%B3/Activity%E7%9A%84%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B.md

1ActivityThread類:
2
3private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
4
5    ...
6    WindowManagerGlobal.initialize();
7    Activity a = performLaunchActivity(r, customIntent);
8    ...
9}

在這裏先調用了WindowManagerGlobal中的初始化方法初始化了WindowManagerService,看名字大概就能知道這是一個WindowManager的服務,通過這個服務可以對頁面進行操作;然後通過調用performLaunchActivity方法生成了一個Activity。

Window的創建過程

上面通過performLaunchActivity方法生成了一個Activity,我們來看看是怎樣生成的:

 1ActivityThread類:
 2
 3private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
 4
 5    ...
 6    Activity activity = null;
 7    try {
 8        activity = mInstrumentation.newActivity(cl, 
 9                component.getClassName(), r.intent);
10    } catch (Exception e) {
11        ...
12    }
13    ...
14
15    if (activity != null) {
16        activity.attach(appContext, this, getInstrumentation(), r.token,
17                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
18                        r.embeddedID, r.lastNonConfigurationInstances, config,
19                        r.referrer, r.voiceInteractor, window, r.configCallback);
20    }
21
22    ...
23}

在這個方法中,通過newActivity這個方法(反射)來生成了一個Activity,生成好了Activity之後就調用Activity中的attach方法,來看一下這個方法裏面幹了些什麼:

 1final void attach(Context context, ActivityThread aThread,
 2            Instrumentation instr, IBinder token, int ident,
 3            Application application, Intent intent, ActivityInfo info,
 4            CharSequence title, Activity parent, String id,
 5            NonConfigurationInstances lastNonConfigurationInstances,
 6            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
 7            Window window, ActivityConfigCallback activityConfigCallback) {
 8
 9        mWindow = new PhoneWindow(this, window, activityConfigCallback);
10        mWindow.setWindowControllerCallback(this);
11        mWindow.setCallback(this);
12        mWindow.setOnWindowDismissedCallback(this);
13        mWindow.getLayoutInflater().setPrivateFactory(this);
14        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
15            mWindow.setSoftInputMode(info.softInputMode);
16        }
17        if (info.uiOptions != 0) {
18            mWindow.setUiOptions(info.uiOptions);
19        }           
20}

果然,在Activityattach方法中創建了一個Window,這個Window就是我們經常聽到的PhoneWindow

View的創建過程

我們大膽的猜測一下,View應該是被添加到Window中的,那麼我們來看一下,到底是怎樣添加的呢?上面說到在handlerLauncher中調用了performLaunchActivity方法,源碼中還調用了handleResumeActivity方法,這個方法是在生命週期onCreate之後,onResume之前調用的,我們來看一下在這個方法中幹了些什麼:

 1final void handleResumeActivity(IBinder token,
 2            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
 3
 4    ...
 5    r = performResumeActivity(token, clearHide, reason);
 6    ...
 7    if (r.window == null && !a.mFinished && willBeVisible) {
 8         r.window = r.activity.getWindow();
 9         View decor = r.window.getDecorView();
10         decor.setVisibility(View.INVISIBLE);
11         ViewManager wm = a.getWindowManager();
12         WindowManager.LayoutParams l = r.window.getAttributes();
13         a.mDecor = decor;
14
15         ...
16         wm.addView(decor, l);
17         ...
18    }           
19}

這裏會先獲取一個WindowDecorView,然後拿到ViewManagerWindowManager的父類),然後調用addView方法,ViewManagerWindowManager都是接口,那麼我們只要到他的實現類WindowManagerImpl中去找addView方法就可以了:

1    @Override
2    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
3        applyDefaultToken(params);
4        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
5    }

這個mGlobal就是我們之前的WindowManagerGlobal,看到這裏相信大家應該有點眉目了吧,最終是由這貨負責把DecorView添加到Window中,在WindowManagerGlobal中的addView方法中還會初始化ViewRootImpl,有興趣的可以自行看源碼瞭解一下

XML中的View是如何添加到DecorView中的這個也不在這裏分析了,可以參考我之前寫的:https://github.com/24Kshign/Android-Knowledge/blob/a8b38bf4765df13fee3a573249a1dc472f3a7e6c/Android%E6%BA%90%E7%A0%81%E7%9B%B8%E5%85%B3/setContentView%E6%BA%90%E7%A0%81.md

總結

啥也不說了,上圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章