Android主項目和Module中R類的區別

咱們知道 Android 項目中會經過自動生成一個 R.java 類的方式來保存項目中全部資源文件的標識。在主項目中生成的 R.java 中的資源聲明是一個靜態常量,而在 module 中它倒是一個靜態變量。這是爲何呢?咱們知道在 java 中若是某個值被聲明成常量(用 final 修飾),則在編譯後,該常量會被直接替換成值。而在 java 語法中,註解的屬性和 switch-case 中的 case 表達式,必須使用常量或者直接使用值,不然會報語法錯誤。下面咱們會展開討論下爲何 module 中的 R 類中聲明的資源標識不是 final 的,這些又致使了哪些現象?html

主項目中

好比你在主項目中建立了一個 activity_main.xml 的佈局文件,則 R.java 中會自動加入一行以下靜態常量。java

public static final class layout {
    ...
    public static final int activity_main=0x7f09001b;
複製代碼

此後你就能夠經過 R.layout.activity_main 的方式使用該資源android

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
複製代碼

咱們編譯上述代碼後獲得 MainActivity.class ,會發現裏面的靜態常量被直接替換成了值。代碼運行過程當中,就能夠直接經過值來找到對應資源了。git

public class MainActivity extends AppCompatActivity {
    public MainActivity() {
    }

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setContentView(2131296283);
    }
}
複製代碼

Module中

而後咱們再在一個 module 中一樣建立一個 MainActivity 和對應的資源,咱們查看該 module 下的 R.javagithub

public static final class layout {
    ...
	public static int activity_main = 0x7f0f001c;
複製代碼

你們有發現區別了嗎?在 module 中添加的該資源少了 final。咱們再來看下 MainActivity.class 文件。咱們會發現此處的資源引用是使用的靜態變量方式,而未直接使用資源的值。bash

public class MainActivity extends AppCompatActivity {
    public MainActivity() {
    }

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setContentView(layout.activity_main);
    }
}
複製代碼

爲何這樣作

Android 中,若是你在 module 中添加了一個資源,就拿這裏的 activity_main.xml 舉例。咱們此處假設若是在 module 中也是 final 的,那會出現什麼狀況?第一,該 module 編譯後的代碼中該資源會被替換成值;第二,當該 module 被添加到主項目中後,若是主項目中有一個一樣名稱的資源,那麼 module 中的該資源就會被替換;第三,主項目中會從新針對該資源生成一個 ID;最終就會出現 module 中那個資源 ID 找不到了。因此呢,這也是爲何 module 中的資源 ID 聲明不使用 final 的緣由。ide

有關資源合併的規則,能夠參考下 google 的官方文檔佈局

https://developer.android.com/studio/write/add-resources.html。gradle

致使的幾個現象

1,這就是爲何當主項目與 module 中有一樣資源時,module 卻會使用主項目的資源。ui

2,這也是爲何咱們在 module 中沒法針對資源使用 switch-case 方式的緣由。

3,這也是爲何咱們沒法在 module 中直接使用 butterknife,由於註解的屬性須要是 final 的。固然如今 butterknife 已經提供了一個解決方案。就是利用 gradle 拷貝一份 R.java 命名成 R2.java,R2.java 裏面的資源聲明都是 final 的。這樣就躲過了語法檢查。固然使用butterknife編譯後的字節碼中使用的仍是R.java中的資源聲明。

做者簡介 彭濤(@彭濤me) 致力於讓技術變得易懂且有趣 我的博客:http://pengtao.me, GitHub地址:https://github.com/CPPAlien

相關文章
相關標籤/搜索