源碼分析 | Activity-setContentView 之我都不帶閃的

我知道你們都很討厭讀別人寫的源碼分析,由於動不動就長篇大論,不講武德,這樣合適嗎,這樣不合適。因而,這是一篇不同的源碼分析,若是看完你還說不懂。年輕人,我勸你:java

耗子尾汁是什麼梗耗子尾汁意思解析及出處介紹-微俠手遊網

引言

普通的一個 Activity-setContentView(),你知道它內部作了什麼嗎?web

概要

image-20201120151757258

源碼分析

咱們先來看一下Activity-setContentView方法:windows

public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}
複製代碼

簡簡單單滴方法,內部調用了 getWindows.setContentView(xxx)api

等等,Windows 是什麼?markdown

Windows 表示一個窗口的概念,Android 中無論是Activity,dialog,仍是 Toast 它們的視圖都是附加在 Windows 上,所以能夠稱 windows 是View的直接管理者。而Windows也只有實現類,即PhoneWindows.ide


咱們接着去看 PhoneWindowssetContentView()svg

@Override
public void setContentView(int layoutResID) {
    if (mContentParent == null) {
        installDecor(); //關注點
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }
     mLayoutInflater.inflate(layoutResID, mContentParent);
}
複製代碼

簡簡單單,內部執行了一個判斷,而後調用 **installDecor() ** 方法。源碼分析

等等,mContenParent是什麼?佈局

mContentParent 即放置咱們本身佈局的容器,你能夠理解爲,它是咱們的根容器,詳情看圖。this


咱們接着去看 **installDecor()**方法:

private void installDecor() {
  	...忽略掉
    mDecor = generateDecor(-1); //關注點1
  	...忽略掉
  	if (mContentParent == null) {
      //關注點2
      mContentParent = generateLayout(mDecor);
    }
  	...忽略掉一大段
}
複製代碼

這個方法內部很繁瑣,很臭很長,咱們須要關注這麼多嗎,不須要,因此直接先進入 generateDecor().

等等,mDecor 是什麼?

mDecorwindows 惟一視圖,也就是咱們 mContentParent 的爸爸。簡稱 DecorView,是否是回憶起了點什麼。


咱們接着去看 generateDecor() 方法

protected DecorView generateDecor(int featureId) {
  	...忽略一大段
    return new DecorView(context, featureId, this, getAttributes());
}
複製代碼

哇,這個方法愛了愛了,直接new了一個 DecorView,其餘也沒啥,返回回去看 installDecor() 中的關注點2-generateLayout().


咱們進入 generateLayout() 方法:

protected ViewGroup generateLayout(DecorView decor) {
   //1
   TypedArray a = getWindowStyle();
   if(xx)else if(xxx)	
   else {
       layoutResource = R.layout.screen_simple;
   }
   //2
   mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
	 ..忽略掉一部分
   //3
   ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
   return contentParent;
}
複製代碼
  1. 顯示獲取當前主題,而後開始判斷究竟要用那個佈局
  2. 將其加載到 DecorView
  3. 經過 findViewById(內部就是DecorView.findViewById)獲取 R.id.content,並返回此viewGroup。

等等,這個 R.layout.screen_simple 是甚?

image-20201121131940286

哦,這就是咱們DecorView中加載的佈局啊,具體大圖以下。

image-20201121173610246

如上圖所示,咱們的佈局最終會被添加到這個根佈局content中。

串一遍思路

咱們接下來將上面的分析總體走一遍:

  • 當咱們調用Activity的 setContentView 時,內部實際上是執行了 PhoneWindows(windows的惟一實例)的 setContenView()
  • PhoneWindowssetContentView() 內部會先判斷當前有沒有佈局容器 contentParent,也即就是有沒有 DecorView,若是沒有,執行 installDecor() 去初始化咱們的 DecorViewcontentParent
  • installDecor() 方法裏面,會先判斷有沒有 DecorView,若是沒有,先new一個出來,而後判斷有沒有 contentParent(承載咱們本身佈局的ViewGroup),沒有的話,就去根據當前主題,選擇一個佈局,並將其當作咱們的根佈局添加到 DecorView 中,再將其中的子view,即R.id.content這個view賦值給咱們的 contentParent
  • 最後 PhoneWindows-setContentView() 方法接下來就能夠將咱們本身的佈局 inflate 進這個根佈局的 contentParent 裏了;
相關文章
相關標籤/搜索