一直對(duì)F碼抱有一種敬畏之心,所以能不看就不看??。雖然看了很多關(guān)于Activity創(chuàng)建流程的技術(shù)文章,但也僅僅是休閑式的,只看不動(dòng)手,當(dāng)時(shí)感覺(jué)看的很明白,沒(méi)過(guò)幾天就又還給作者了,下次遇見(jiàn)此類(lèi)問(wèn)題,還是一臉懵逼。痛定思痛,決定自己看一下F碼,再做個(gè)筆記,加深印象,也便于回顧。
大家都聽(tīng)說(shuō)過(guò)Activity,Window,PhoneWindow,WindowManager,WindowManagerImpl,WindowManagerGlobal,WindowManagerServer,ViewRoot,ViewRootImpl等這些class吧,如果你和我一樣對(duì)它們的關(guān)系一知半解,那么這個(gè)筆記很適合你。最好打開(kāi)AS,跟著源碼走一走
表演開(kāi)始,這次不要??,會(huì)不會(huì)又跑路?????
首先在ActivityThread的performLaunchActivity方法通過(guò)反射創(chuàng)建Activity,activity調(diào)用attach方法創(chuàng)建PhoneWindow;activity執(zhí)行onCreate生命周期,setContentView(int)經(jīng)過(guò)層層調(diào)用執(zhí)行PhoneWindow的setContentView(View)方法,然后創(chuàng)建根布局DecorView,DecorView包含一個(gè)contentParent,我們setContentView就是把自己的頁(yè)面添加到contentParent里面,現(xiàn)在頁(yè)面已經(jīng)建成,但還沒(méi)有顯示,接下來(lái)看ActivityThread的handleResumeActivity方法,activity調(diào)用makeVisible方法,mDecor.setVisibility(View.VISIBLE)顯示
先說(shuō)一下Window
有View的地方就有Window
Window分三大類(lèi),本文所講的Window是應(yīng)用程序Window
系統(tǒng)Window
例如Toast、輸入法、低電量提示所對(duì)應(yīng)的window應(yīng)用程序Window
例如Activity所對(duì)應(yīng)的window。每個(gè)Activity都有一個(gè)window,通過(guò)getWindow獲取,這里的返回的Window實(shí)際上PhoneWindow,Window是一個(gè)抽象類(lèi),具體實(shí)現(xiàn)類(lèi)就是PhoneWindow子Window
例如PopWindow
在WindowManager里面可以看到又對(duì)Window的種類(lèi)進(jìn)行了細(xì)化,細(xì)化后的每種類(lèi)型的Window都對(duì)應(yīng)一個(gè)int類(lèi)型的常量值,這個(gè)值越大,在Window層疊的時(shí)候就越靠上
Activity和Window的創(chuàng)建
ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
//通過(guò)反射創(chuàng)建一個(gè)Activity
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
...
//調(diào)用attach(...),創(chuàng)建Window
activity.attach(...);
...
//調(diào)用callActivityOnCreate(...),Activity執(zhí)行onCreate
mInstrumentation.callActivityOnCreate(...);
...
return activity;
}
Activity.java
final void attach(...) {
...
//創(chuàng)建Window
mWindow = new PhoneWindow(this, window, activityConfigCallback);
...
}
頁(yè)面顯示
Activity.java
調(diào)用父類(lèi)AppCompatActivity的setContentView方法
setContentView(R.layout.activity_main);
AppCompatActivity.java
AppCompatDelegate是一個(gè)接口,getDelegate返回AppCompatDelegate的實(shí)現(xiàn)類(lèi)AppCompatDelegateImpl,所以此處又調(diào)用AppCompatDelegateImpl的setContentView(int)方法
public void setContentView(@LayoutRes int layoutResID) {
this.getDelegate().setContentView(layoutResID);
}
@NonNull
public AppCompatDelegate getDelegate() {
if (this.mDelegate == null) {
this.mDelegate = AppCompatDelegate.create(this, this);
}
return this.mDelegate;
}
public static AppCompatDelegate create(Activity activity, AppCompatCallback callback) {
return new AppCompatDelegateImpl(activity, activity.getWindow(), callback);
}
AppCompatDelegateImpl.java
public void setContentView(int resId) {
this.ensureSubDecor(); //重要方法,安裝DecorView
ViewGroup contentParent = (ViewGroup)this.mSubDecor.findViewById(16908290);
contentParent.removeAllViews();
LayoutInflater.from(this.mContext).inflate(resId, contentParent);
this.mOriginalWindowCallback.onContentChanged();
}
private void ensureSubDecor() {
if (!this.mSubDecorInstalled) {
this.mSubDecor = this.createSubDecor();
...
}
...
}
private ViewGroup createSubDecor() {
...
//mWindow是PhoneWindow
this.mWindow.getDecorView();
...
}
PhoneWindow.java
生成跟布局DecorView,DecorView繼承FrameLayout,包括標(biāo)題欄和內(nèi)容部分(mContentParent),我們setContentView就是把view添加到mContentParent
@Override
public final View getDecorView() {
if (mDecor == null || mForceDecorInstall) {
installDecor();
}
return mDecor;
}
private void installDecor() {
...
if (mDecor == null) {
mDecor = generateDecor(-1);
...
}
if (mContentParent == null) {
//內(nèi)容布局,Activity里面的setContentView就放到mContentParent里面
mContentParent = generateLayout(mDecor);
}
...
//把我們的布局添加到Content里面
mContentParent.addView(view, params);
...
}
protected DecorView generateDecor(int featureId) {
...
return new DecorView(context, featureId, this, getAttributes());
}
protected ViewGroup generateLayout(DecorView decor) {
...
//findViewById調(diào)用DecorView的findViewById,contentParent是DecorView的id為com.android.internal.R.id.content的子view
//Window的常量 public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
...
return contentParent;
}
ActivityThread.java
回到ActivityThread
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,String reason) {
...
//顯示View
r.activity.makeVisible();
...
}
Activity.java
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
//顯示DecorView
mDecor.setVisibility(View.VISIBLE);
}
到此頁(yè)面已經(jīng)顯示了,那么WindowManager怎么讓W(xué)indow顯示在頁(yè)面上的?下篇再進(jìn)行分析...
第一次寫(xiě)技術(shù)文章,錯(cuò)誤之處請(qǐng)包涵并指正
Thanks
End