1. 程式人生 > >#Android原始碼#View的構造方法為什麼要4個?

#Android原始碼#View的構造方法為什麼要4個?

問題描述

在View中發現有四個構造方法(5.0下是三個),如下,有什麼玄妙嗎?

//C1
public View(Context context) {
    ....
}
//C2
public View(Context context, @Nullable AttributeSet attrs) {
    this(context, attrs, 0);
}
//C3
public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    this(context, attrs, defStyleAttr, 0
); } //C4 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { this(context); .... }

問題探討

說白點,這是Android逐漸新增功能對低版本相容的方式。
比如四個引數的構造方法的最後那個引數,是最近才加入的,為了保證低版本相容,原來三個引數的構造方法還需要保留,這時候就直接讓三引數的構造方法帶上一個第四引數的預設值呼叫第四引數,就可以避免寫很多重複的程式碼了。

—-有明

C1是最簡單的一個,如果你只打算用code動態建立一個view而不使用佈局檔案xml inflate,那麼實現C1就可以了。

C2多了一個AttributeSet型別的引數,在通過佈局檔案xml建立一個view時,這個引數會將xml裡設定的屬性傳遞給建構函式。如果你採用xml inflate的方法卻沒有在code裡實現C2,那麼執行時就會報錯。但是由於編譯能順利通過,對於我這樣的菜鳥,這個錯誤有時不太容易被發現。

C3,在程式碼比如xml裡通過某種方式指定了view的style時,C3在該view被inflate時呼叫,並將style傳入給defStyle。方式大概有兩種,一種是在直接在佈局檔案該view標籤裡使用style="@style/customstyle"
來指定,另一種是採用指定theme的方式,在AndroidManifest.xml的application標籤裡使用android:theme="@style/customstyle"

在styles.xml裡另外定義一個style作為theme:

<style name="purpletheme">
     <item name="ourstyle">@style/purple</item>
</style>

在AndroidManifest.xml的Application標籤中應用theme:

android:theme="style/purpletheme"

這兩種指定屬性的方法不同,在程式裡引用這個屬性的方法也不同。theme指定的屬性,可以直接用R.attr.ourstyle來引用,也可以用R.styleable.CustomView[R.styleable.CustomView_ourstyle]來引用,於是:

 //C2
 public CustomView(Context context, AttributeSet attrs) {
     this(context, attrs, R.attr.ourstyle );
 }

這樣就成功地讓defStyle生效了。

那麼直接在標籤裡賦值的屬性怎麼引用呢?
直接在標籤裡賦值的屬性,都會在xml inflate時通過AttributeSet這個引數傳給C2,所以我們可以通過AttributeSet類提供的getAttributeResourceValue方法來獲取屬性的值。但是很可惜的是,我們只能獲取到屬性的值,而無法獲取包含這個值的屬性的引用(getAttributeNameResource方法返回的是和R.attr.ourstyle一樣的值,但這時R.attr.ourstyle並未指向@style/purple)

—-木人巷

C4,可以直接獲取傳入資源ID,如R.style.purple

總結(在原始碼中有詳細的說明)

  1. 構造方法的過載是為了方便擴充套件和相容
  2. Context context:接收上下文物件
  3. @Nullable AttributeSet attrs:接收從xml中裝載的屬性集
  4. int defStyleAttr:設定預設的樣式屬性id,值來源如:<attr format="reference" name="drawerArrowStyle"/>
  5. int defStyleRes:設定預設的樣式資源id,值來源如:<declare-styleable name="ActionBarLayout"><attr name="android:layout_gravity"/></declare-styleable>
  6. 構造方法C1,通常在程式碼中動態建立View時使用
  7. 構造方法C2,當從xml中inflate時系統呼叫
  8. 其它構造方法,顯式在C1/C2中呼叫,否則不會呼叫