Activity頁(yè)面加載流程(一)

一直對(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

  1. 系統(tǒng)Window
    例如Toast、輸入法、低電量提示所對(duì)應(yīng)的window

  2. 應(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

  3. 子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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容