欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android?nonTransitiveRClass資源沖突問題淺析

 更新時(shí)間:2022年12月13日 11:35:53   作者:TechMerger  
這篇文章主要介紹了Android?nonTransitiveRClass資源沖突問題,別搞錯(cuò)了,nonTransitiveRClass不能解決資源沖突,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧

前言

nonTransitiveRClass:非傳遞性 R 類的屬性,在 gradle.properties 文件里使用。

不少開發(fā)者可能聽過它,但了解可能僅限于是對(duì) R 文件做了優(yōu)化,甚至以為它可以解決資源沖突!但它到底做了什么優(yōu)化、能否解決資源沖突,則鮮少有機(jī)會(huì)去了解。

本文通過該屬性使用前后對(duì)比、在資源沖突場(chǎng)景下的表現(xiàn)等角度去充分解讀它。

使用前后對(duì)比

假使我們的 Project 包含兩個(gè)子 Module:Common 和 Recommend。

其中 Common Module 的包名為 com.example.common,提供共通的資源。比如:

?<!-- common/.../strings.xml  -->
?<resources>
? ? ?<string name="common_error">發(fā)生了錯(cuò)誤,請(qǐng)檢查鏈路</string>
?</resources>

而 Recommend Moudle 的包名為 com.example.recommend,提供其獨(dú)有的資源。比如:

?<!-- recommend/.../strings.xml  -->
?<resources>
? ? ?<string name="recommend_error">沒有推薦內(nèi)容,稍后再試</string>
?</resources>

當(dāng) Recommend Moudle 收到錯(cuò)誤的時(shí)候,會(huì)根據(jù)類型展示相應(yīng)的說明。

?package com.example.recommend
?sealed class Error(val tipId: Int) {
? ? ?// 來自 Common 包的資源
? ? ?class Common ? ?  : Error(R.string.common_error)
? ? ?class Recommend ? : Error(R.string.recommend_error)
? ? ?// 來自 AppCompat 包的資源
? ? ?class BarCollapse : Error(R.string.abc_toolbar_collapse_description)
?}

可以看到即便使用了不同 Module 的資源文件,R 文件的包名也無需進(jìn)行區(qū)分。而這樣的寫法能否通過編譯,其實(shí)跟 AGP 的版本、AS 的版本均有關(guān)系。

  • 2020 年 8 月發(fā)布的 AGP 4.1 將前期用于 R 文件優(yōu)化的 namespacedRClass 實(shí)驗(yàn)性屬性替換成了 nonTransitiveRClass(默認(rèn) false)。以便其 R 類僅包含庫本身中聲明的資源,而不包含庫的依賴項(xiàng)中的任何資源,從而縮減相應(yīng)庫的 R 類大小。
  • 2022 年 01 月 18 日發(fā)布的 Android Studio Bumblebee 則將新項(xiàng)目的該屬性默認(rèn)開啟。

屬性關(guān)閉

假使將 namespacedRClass 或 nonTransitiveRClass 屬性指定為 false,或者沒有使用這倆屬性、且 AS 處于 Bumblebee 之前的版本,上述的寫法都是可以通過編譯的。

原因顯而易見 Recommend Module 的 R 文件包含了被依賴的 Common Module 的資源 ID。

可話雖如此,你真的打開過這種情況下的 R 文件嗎?知道它有多龐大嗎?

我們?cè)陧?xiàng)目根目錄下搜索 R 文件的位置:

 ellisonchan@bogon AndroidTDemo % find . -name "R.*"
 ./recommend/build/intermediates/compile_r_class_jar/debug/R.jar
 ./recommend/build/intermediates/compile_symbol_list/debug/R.txt

沒有找到 R.java,只有有同名的 txt 和 jar。可以直接打開 txt 或使用 Jar 工具查看。

先看下 R.txt,實(shí)際上它有 *4000+ *行,太過龐大,這里只保留 Recommend Module 自身以及極少量其他被依賴的 Module 的資源定義。

?// R.txt
?// 其他被依賴的 Module 定義的資源
?int anim abc_fade_in 0x0
?int anim abc_fade_out 0x0
?int anim abc_grow_fade_in_from_bottom 0x0
?int anim abc_popup_enter 0x0
?int anim abc_popup_exit 0x0
?...
?// 以下是 Recoomend Module 定義的資源
?int color black 0x0
?...
?int color purple_200 0x0
?int color purple_500 0x0
?int color purple_700 0x0
?...
?int color teal_200 0x0
?int color teal_700 0x0
?...
?int color white 0x0
?...
?int drawable ic_launcher_background 0x0
?int drawable ic_launcher_foreground 0x0
?...
?int mipmap ic_launcher 0x0
?int mipmap ic_launcher_round 0x0
?...
?int style Theme_AndroidTDemo 0x0
?...
?int string recommend_error 0x0
?...
?// 以下是被依賴的 Common Module 定義的資源
?int string common_error 0x0
?// 其他被依賴的 Module 定義的資源
?...
?int xml standalone_badge 0x0
?int xml standalone_badge_gravity_bottom_end 0x0
?int xml standalone_badge_gravity_bottom_start 0x0
?int xml standalone_badge_gravity_top_start 0x0
?int xml standalone_badge_offset 0x0

R.jar 的內(nèi)容更多,足足 *5000+ *行,因其除了 ID 列表,還包含了各種二級(jí)資源類型 class 定義(和上面一樣只列出部分內(nèi)容)。

?// R.jar
?package com.example.recommend;
?public final class R {
? ?public static final class anim {
? ? ?public static int abc_fade_in = 0;
? ? ?public static int abc_fade_out = 0;
? ? ?public static int abc_grow_fade_in_from_bottom = 0;
? ? ?public static int abc_popup_enter = 0;
? ? ?public static int abc_popup_exit = 0;
? ?  ...
?  }
?  ...
? ?public static final class color {
? ?  ...
? ? ?public static int black = 0;
? ?  ...
? ? ?public static int purple_200 = 0;
? ? ?public static int purple_500 = 0;
? ? ?public static int purple_700 = 0;
? ?  ...
? ? ?public static int teal_200 = 0;
? ? ?public static int teal_700 = 0;
? ?  ...
? ? ?public static int white = 0;
?  }
? ?public static final class dimen { ... }
? ?public static final class drawable {
? ?  ...
? ? ?public static int ic_launcher_background = 0;
? ? ?public static int ic_launcher_foreground = 0;
? ?  ...
?  }
? ?public static final class id { ... }
? ?public static final class integer { ... }
? ?public static final class interpolator { ... }
? ?public static final class layout { ... }
? ?public static final class mipmap {
? ? ?public static int ic_launcher = 0;
? ? ?public static int ic_launcher_round = 0;
?  }
? ?public static final class plurals { ... }
? ?public static final class string {
? ?  ...
? ? ?public static int common_error = 0;
? ?  ...
? ? ?public static int recommend_error = 0;
? ?  ...
?  }
? ?public static final class style {
? ?  ...
? ? ?public static int Theme_AndroidTDemo = 0;
? ?  ...
? ? ?public static int Theme_AppCompat = 0;
? ?  ...
? ?}
? ?public static final class styleable { ... }
? ?public static final class xml {
? ? ?public static int standalone_badge = 0;
? ? ?public static int standalone_badge_gravity_bottom_end = 0;
? ? ?public static int standalone_badge_gravity_bottom_start = 0;
? ? ?public static int standalone_badge_gravity_top_start = 0;
? ? ?public static int standalone_badge_offset = 0;
?  }
?}

可以看到 Recommend Module 只定義了 10 多個(gè)資源,但 R 文件卻從其他 Module 導(dǎo)入了近 *3900+ *個(gè)資源。

這里拎出部分資源,看看是從哪個(gè)包導(dǎo)進(jìn)來的。

abc_fade_in 等 anim 資源:來自于 AppCompat 包。

standalone_badge 等 xml 資源:來自于 Material 包。

這些都來源于 build.gradle 的 dependency。

屬性開啟

事實(shí)上這些資源中的大部分,我們都是不會(huì)使用的。早期的這種不管實(shí)際使用,而一股腦將被依賴的 Module 資源 ID 全部囊括進(jìn)來的作法是不太合適的。

當(dāng)將 android.nonTransitiveRClass 屬性改為 true,就不會(huì)執(zhí)行上述作法,但上述的寫法會(huì)發(fā)生編譯錯(cuò)誤:

Unresolved reference: common_error

Unresolved reference: abc_toolbar_collapse_description

很明顯,我們應(yīng)當(dāng)明確指定 common_error 和 abc_toolbar_collapse_description 資源的 R 文件包名才行。

?sealed class Error(val tipId: Int) {
? ? ?class Common ? ?  : Error(com.example.common.R.string.common_error)
? ?  ...
? ? ?class BarCollapse : Error(androidx.appcompat.R.string.abc_toolbar_collapse_description)
?}

原因很好理解,依賴包的資源 ID 沒有被囊括進(jìn)自己的 R 文件。新的 R.txt 也顯示其僅包括本 Module 定義的資源。

?// R.txt
?int color black 0x0
?int color purple_200 0x0
?int color purple_500 0x0
?int color purple_700 0x0
?int color teal_200 0x0
?int color teal_700 0x0
?int color white 0x0
?int drawable ic_launcher_background 0x0
?int drawable ic_launcher_foreground 0x0
?int mipmap ic_launcher 0x0
?int mipmap ic_launcher_round 0x0
?int string recommend_error 0x0
?int style Theme_AndroidTDemo 0x0

R.jar 中也是一樣。

?// R.jar
?package com.example.recommend;
?public final class R {
? ?public static final class color {
? ? ?public static int black = 0;
? ? ?public static int purple_200 = 0;
? ? ?public static int purple_500 = 0;
? ? ?public static int purple_700 = 0;
? ? ?public static int teal_200 = 0;
? ? ?public static int teal_700 = 0;
? ? ?public static int white = 0;
?  }
? ?public static final class drawable {
? ? ?public static int ic_launcher_background = 0;
? ? ?public static int ic_launcher_foreground = 0;
?  }
? ?public static final class mipmap {
? ? ?public static int ic_launcher = 0;
? ? ?public static int ic_launcher_round = 0;
?  }
? ?public static final class string {
? ? ?public static int recommend_error = 0;
?  }
? ?public static final class style {
? ? ?public static int Theme_AndroidTDemo = 0;
?  }
?}

開啟并自動(dòng)遷移

上面的示例使用其他包的資源的邏輯極少,手動(dòng)修改 R 文件不繁瑣。但當(dāng)大型項(xiàng)目開啟了 android.nonTransitiveRClass 屬性,修改各 R 文件名稱的工作量很大、還易錯(cuò)。

這時(shí)候可以采用自 Android Studio Arctic Fox 版本引入的重構(gòu)工具來自動(dòng)完成,避免手動(dòng)啟用之后、自己逐步修改的麻煩。

運(yùn)行 Menu -> Refactor -> Migrate to Non-transitive R Classes

這時(shí)候 AS 會(huì)提醒你將修改如下代碼進(jìn)行遷移。

選擇繼續(xù)之后,可以看到引用的其他包的 R 包被自動(dòng)補(bǔ)全了。

 sealed class Error(val tipId: Int) {
     class Common      : Error(com.example.common.R.string.common_error)
     class Recommend   : Error(R.string.recommend_error)
     class BarCollapse : Error(androidx.appcompat.R.string.abc_toolbar_collapse_description)
 }

能否解決資源沖突

現(xiàn)在我們來探討 android.nonTransitiveRClass 屬性能否解決資源沖突的問題。

假使我們?cè)?Recommend Module 中也定義了名為 common_error 的資源。

?<!-- recommend/.../strings.xml  -->
?<resources>
? ? ?<string name="recommend_error">沒有推薦內(nèi)容,稍后再試</string>
? ? ?<string name="common_error">發(fā)生了錯(cuò)誤,請(qǐng)檢查推薦鏈路</string>
?</resources>

對(duì)于 Recommend Module 而言,使用 common_error 資源的地方肯定會(huì)覆蓋 Common Module 的重復(fù)定義,無須多言。

而對(duì)于使用這兩者的 App Module 而言,因 Module 引用順序的不同,其可能會(huì)使用 Recommend,也可能使用 Common 的定義。即最終編譯進(jìn)來的只有一份定義。

如下的 App、Common、Recommend 3 個(gè) Module 的 R.java 文件也說明了這點(diǎn),3 個(gè) common_error 的數(shù)值完全相同。

?// R.java in App Module
?package com.example.tiramisu_demo;
?public final class R {
?  ...
? ?public static final class string {
? ? ?public static final int common_error = 2131689515;
? ?  ...
?  }
?}
?// R.java in Common Module
?package com.example.common;?
?public final class R {
?  ...
? ?public static final class string {
? ? ?public static final int common_error = 2131689515;
? ?  ...
?  }
?  ...
?}
?// R.java in Recommend Module
?package com.example.recommend;
?public final class R {
?  ...
? ?public static final class string {
? ? ?public static final int common_error = 2131689515;
? ?  ...
?  }
?  ...
?}

在 App Module 的 Activity 類里測(cè)試下效果:

?class MainActivity : AppCompatActivity() {
? ? ?override fun onCreate(savedInstanceState: Bundle?) {
? ? ? ?  ...
? ? ? ? ?val dynamicTextView: TextView = findViewById(R.id.dynamic_test)
? ? ? ? ?handleError(
? ? ? ? ? ? ?Error.Common(),
? ? ? ? ? ? ?dynamicTextView,
? ? ? ? ? ? ?this@MainActivity
? ? ? ?  )
? ?  }
?}
?fun handleError(
? ? ?error: Error,
? ? ?textView: TextView,
? ? ?context: Context
?) {
? ? ?error.tipId.let { id ->
? ? ? ? ?context.getText(id).let { content ->
? ? ? ? ? ? ?textView.text = content
? ? ? ?  }
? ?  }
?}
?sealed class Error(val tipId: Int) {
? ? ?class Common ? ?  : Error(R.string.common_error)
? ? ?class Recommend ? : Error(R.string.recommend_error)
? ? ?class BarCollapse : Error(R.string.abc_toolbar_collapse_description)
?}

運(yùn)行下可以看到展示的是 Recommend Module 定義的資源內(nèi)容:

之后,我們?cè)偈褂们懊嫣峒暗?android.nonTransitiveRClass 自動(dòng)遷移工具嘗試更改下 R 文件的配置問題。

如下的工具遷移提醒可以看到:只能將待遷移資源的 R 遷移到目前使用來源 Module 的 R,即無法識(shí)別多個(gè)來源。

遷移后的代碼:

 sealed class Error(val tipId: Int) {
     class Common      : Error(com.example.recommend.R.string.common_error)
     class Recommend   : Error(com.example.recommend.R.string.recommend_error)
     class BarCollapse : Error(androidx.appcompat.R.string.abc_toolbar_collapse_description)
 }

初步可以看到 nonTransitiveRClass 屬性并不能幫你自動(dòng)解決資源沖突,只是強(qiáng)制要求你將各 Module 的資源按其所屬包名區(qū)分開來使用。

當(dāng)沖突發(fā)生的地方,你可以通過包名進(jìn)行區(qū)分。

比如讓 Common Error 展示 Common Module 下的 common_error 資源。

?sealed class Error(val tipId: Int) {
? ? ?class CommonRecommend ?  : Error(com.example.recommend.R.string.common_error)
? ? ?class Common ?  : Error(com.example.common.R.string.common_error)
? ?  ...
?}

但這種寫法真的有用嗎?

再運(yùn)行下,竟發(fā)現(xiàn)沒有任何作用,仍然展示的是 Recommend Module 中的資源。

此刻,你可能已經(jīng)領(lǐng)悟到:為什么用即便用包名區(qū)分了沖突的資源,但仍然沒有任何作用?

這是因?yàn)橘Y源沖突導(dǎo)致 AAPT 仍然只打包了一份資源,nonTransitiveRClass 屬性只是不再將 common_error 等其他被依賴的資源 ID 囊括到 App 的 R 文件中而已。

同一份資源 ID,通過 com.example.common.R 來引用,還是 com.example.recommend.R 來引用,沒有區(qū)別!

結(jié)語

上面的示例可以看到,沒有開啟 nonTransitiveRClass 的話,僅僅定義 10 多個(gè)資源的 Module 的 R 文件會(huì)激增到 4000+ 個(gè) ID。這對(duì)編譯速度、AAR / APK 體積的影響是可以預(yù)見的。

加上模塊化開發(fā)的流行,Module 的龐雜必然引發(fā) ID 的大量重復(fù)定義,進(jìn)而導(dǎo)致 R 文件指數(shù)膨脹。另外 App 構(gòu)建的時(shí)候,會(huì)為項(xiàng)目的每個(gè)依賴 Module 生成一個(gè) R.java 文件,然后將這些 R 文件和應(yīng)用的其他類一起編譯。

這兩個(gè)因素將極大地拖累多模塊的構(gòu)建效率。

而當(dāng)開啟了 nonTransitiveRClass 屬性,可以保證每個(gè) Module 的 R 文件將只會(huì)包含自己聲明的資源,依賴項(xiàng)中的資源會(huì)被排除在外。這樣一來,R 文件大小將會(huì)顯著減少。

另外,AGP 會(huì)直接生成包含應(yīng)用的已編譯 R.jar,而不會(huì)先編譯其中間的 R.java 文件。這項(xiàng)優(yōu)化可以確保,向運(yùn)行時(shí)依賴 Module 中添加新資源時(shí),可以避免重新編譯下游 Module。

這兩項(xiàng)變化將大大提升模塊化的構(gòu)建速度,并減小 AAR / APK 的體積~

另外,我們必須認(rèn)識(shí)到 nonTransitiveRClass 屬性跟資源沖突沒有關(guān)系,它是用來優(yōu)化 R 文件構(gòu)成的,不是也不能解決資源沖突。資源沖突仍然要依賴開發(fā)者對(duì)于資源的規(guī)范定義和使用!

到此這篇關(guān)于Android nonTransitiveRClass資源沖突問題淺析的文章就介紹到這了,更多相關(guān)Android nonTransitiveRClass內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android學(xué)習(xí)筆記(二)之電話撥號(hào)器

    Android學(xué)習(xí)筆記(二)之電話撥號(hào)器

    目前手機(jī)市場(chǎng)上android已經(jīng)具有強(qiáng)大的霸主地位,吸引了很多的追棒者,android學(xué)習(xí)越來越火熱,本文給大家介紹android學(xué)習(xí)筆記(二)之電話撥號(hào)器,感興趣的朋友一起學(xué)習(xí)吧
    2015-11-11
  • Android?Activity通用懸浮可拖拽View封裝的思路詳解

    Android?Activity通用懸浮可拖拽View封裝的思路詳解

    這篇文章主要介紹了Android?Activity通用懸浮可拖拽View封裝,實(shí)現(xiàn)思路是通過封裝通用的基礎(chǔ)懸浮View,繼承通用View,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07
  • RxJava構(gòu)建流基本原理示例解析

    RxJava構(gòu)建流基本原理示例解析

    這篇文章主要為大家介紹了RxJava構(gòu)建流基本原理示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • android輪播圖組件的制作方法

    android輪播圖組件的制作方法

    這篇文章主要為大家詳細(xì)介紹了android輪播圖組件的制作方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • 詳解Android Dialog對(duì)話框的五種形式

    詳解Android Dialog對(duì)話框的五種形式

    這篇文章主要為大家詳細(xì)介紹了Android對(duì)話框的五種形式,一般對(duì)話框,列表對(duì)話框,單選按鈕對(duì)話框,多選按鈕對(duì)話框,自定義對(duì)話框,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Android Toast的幾種使用方式及注意事項(xiàng)

    Android Toast的幾種使用方式及注意事項(xiàng)

    Toast是Android中常用的組件,下面介紹下Toast使用的幾種方式和注意事項(xiàng),本文給大家分享Toast的使用方式,感興趣的朋友一起看看吧
    2024-02-02
  • Android基于OpenCV實(shí)現(xiàn)圖像脫色

    Android基于OpenCV實(shí)現(xiàn)圖像脫色

    脫色是將彩色圖像轉(zhuǎn)換為灰度圖像的過程。同時(shí),它也是數(shù)字打印,風(fēng)格化的黑白照片渲染以及許多單通道圖像處理應(yīng)用程序中的基本工具。本文講述基于OpenCV實(shí)現(xiàn)圖像脫色的步驟
    2021-06-06
  • Android實(shí)現(xiàn)簡(jiǎn)單加法計(jì)算器

    Android實(shí)現(xiàn)簡(jiǎn)單加法計(jì)算器

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)簡(jiǎn)單加法計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • Android編程之線性布局LinearLayout實(shí)例簡(jiǎn)析

    Android編程之線性布局LinearLayout實(shí)例簡(jiǎn)析

    這篇文章主要介紹了Android編程之線性布局LinearLayout用法,結(jié)合實(shí)例形式簡(jiǎn)單分析了Android線性布局的使用技巧,需要的朋友可以參考下
    2016-01-01
  • Android SQLite詳解及示例代碼

    Android SQLite詳解及示例代碼

    本文主要講解Android SQLite,這里對(duì)數(shù)據(jù)庫SQLite 做了詳細(xì)的知識(shí)資料整理,并附示例代碼和實(shí)現(xiàn)效果圖,有需要的小伙伴可以參考下
    2016-08-08

最新評(píng)論