今天來回味下組件化和模塊化屋休,這2種說法時一回事,當(dāng)然還是有區(qū)別的,下面再詳細(xì)說酱鸭,其實很簡單吗垮,只是設(shè)計范圍的不同,也都是約定俗成的東西凛辣。為了方便我下面都說組件化了
到現(xiàn)在組件化真的不是什么新鮮東西了抱既,大公司都用的滾瓜爛熟,龍飛鳳舞了扁誓,也就是現(xiàn)在部分中型項目和小項目在組件化的路上努力防泵。所以同志們,組件化沒玩過的蝗敢,不熟悉的趕緊搞起來捷泞,說一點,你不會組件化寿谴,發(fā)布影子工程那么對你來說就是個噩夢锁右。從本質(zhì)上來講任何技術(shù)進(jìn)步都是在現(xiàn)實需求的逼迫下抓耳撓腮,耗盡無數(shù)頭發(fā)才想出來的讶泰。哈哈咏瑟,這里說個笑話罷了。所以呢組件化這個東西出來這么久了痪署,頁發(fā)展了這么久了码泞,用的人越來越多,那肯定是對我們顯示開發(fā)大有裨益的狼犯,下伙伴們不會余寥,不熟悉抓緊啦,要不面試問你你怎么回答呢悯森!
下面來正式說說組件化
組件化這個東西其實并不復(fù)雜宋舷,他就是種思路,本質(zhì)上是一種 app 架構(gòu)思路瓢姻,說穿了很簡單的祝蝠,難在組件化改造的時候,真正寫起代碼會出現(xiàn)不少棘手的問題幻碱,當(dāng)然這些坑基本前人都趟完了绎狭,這里我主要時記錄下,要是你看到熟悉的部分收班,請不要罵我啊坟岔,畢竟都是前輩們的東西啊。
這里補充一下摔桦,組件化時一種 app 架構(gòu)社付,他的發(fā)展也是沿著正常的技術(shù)發(fā)展脈絡(luò)來的承疲,也是為了以追求高復(fù)用,高可維護(hù)性的目的的代碼封裝鸥咖,區(qū)別是組件化是對整個 app 的再次封裝燕鸽。
廢話了這么多,那么什么是組件化呢,各位看官想不要著急,在詳細(xì)說組件化之前凸主,我們要搞懂2個概念,就是上面說的組件和模塊党远。
首先組件和模塊都不是官方規(guī)定的,都是這些技術(shù)發(fā)展下來大家約定俗成的概念富弦,其實很簡單沟娱,一說就明白
模塊:android 中的模塊就是業(yè)務(wù)模塊,單指業(yè)務(wù)腕柜,是按照業(yè)務(wù)對 app 進(jìn)行拆分济似,比如說訂單我們搞成一個模塊,個人中心我們搞成一個模塊盏缤,視頻砰蠢,音頻這些都搞成模塊,在app中的體現(xiàn)就是 一個個module唉铜,module 的中文意思也是模塊台舱,這不準(zhǔn)這就是 google 對我們的暗示呢。模塊化的目的時為了搭積木打毛,隨便拿幾個模塊module 出來就可以誰誰便便的上線一個 app柿赊,你還別說現(xiàn)在影子 app 的需求很旺盛俩功,你去看看大公司的項目那個不是一堆影子工程幻枉,頭條還搞出一個頭條視頻的馬甲呢,這其實就是把視頻 module 拿出來诡蜓,加上一個啟動頁熬甫。這樣的例子是比比皆是的,要不說不會組件化影子工程對你就是噩夢呢蔓罚,哈哈椿肩,到時候維護(hù)那是想也別想了,代碼你要搞多少份啊豺谈。
組件:這個一樣簡單啊郑象,說穿了就是我們平時干的事,對功能的封裝茬末,這就是組件厂榛,一個功能就是一個組件盖矫,IO,數(shù)據(jù)庫击奶,網(wǎng)絡(luò)等等這些功能都是組件辈双,這么說你就明白了吧。既然這樣那為毛線我們還要搞出來這個一個組件的概念柜砾,當(dāng)然了任何事都是有其意義的湃望,因為組件對功能代碼的封裝有個很高了明確的要求:一處封裝,處處使用痰驱。要我們把維護(hù)性证芭,復(fù)用性,擴(kuò)展性担映,性能做到極致檩帐,因為這樣才能真正做到一處封裝,處處使用另萤。當(dāng)然組件的范圍現(xiàn)在也是覆蓋的很廣的湃密,app 中的一切都是組件,基本上我們分為:基礎(chǔ)功能組件四敞,通用UI組件泛源,基礎(chǔ)業(yè)務(wù)組件。
以上我談了下我自己對于模塊化忿危,組件化的理解达箍,是目前開發(fā)中對于模塊和組件的理解。在模塊化和組件化的發(fā)展中概念也是有些調(diào)整變化的铺厨,大家只要看現(xiàn)在時什么樣子就好了缎玫,深入學(xué)習(xí)的話有興趣可以看看組件化,模塊化的發(fā)展歷程解滓。
我認(rèn)為 Android 模塊化探索與實踐 對于模塊化赃磨,組件化概念的解釋時最優(yōu)秀的。
組件化和模塊化在現(xiàn)在看是一回事了洼裤,如果把一個項目看成是袋中的組合的話邻辉,那么模塊就是體積最大的哪些袋子,組件就是體積小的袋子腮鞍,大的袋子是最直接可被外接觀測和接觸的袋子值骇,大的袋子也是用小的袋子組成的,一個不太恰當(dāng)?shù)谋扔靼梢乒K和組件就是這樣的關(guān)系吱瘩,是我們對業(yè)務(wù)和功能拆分,封裝的理解迹缀。
好了正式開始介紹了組件化啦
組件化在工程表現(xiàn)上就是我們把 app 按照其業(yè)務(wù)的不同使碾,劃分為不同的 module模塊皱卓,把各種功能封裝成一個個 library,module 之間時嚴(yán)格禁止橫向依賴的部逮,要不怎么單獨使用呢娜汁,我不能為了用一個 module,把相關(guān)的module 都帶上吧兄朋,要是這么 module 還有依賴的module 呢掐禁,這樣談復(fù)用性就是扯淡了。
主 app 就是我們常說的殼工程依賴這些 module颅和,library 由需求的 module 依賴傅事,但是要考慮library 版本的問題,隨著業(yè)務(wù)和功能的擴(kuò)展峡扩,library 的數(shù)量也是巨大的蹭越,微信在組件化拆分時據(jù)說拆分出80多個 module,可見 library 也是少不了的教届。
module 和 library 多數(shù)時候我們時提供arr 和 jar 來給殼工程引用的响鹃,arr 和 jar 在編譯時是不會再編譯的,只會檢查版本案训,保留一個最新的版本买置,既提高了 app 的編譯速度,頁提供一種資源沖突解決方式强霎。
下面我方一些圖來描述一下組件化忿项,大伙仔細(xì)看看,圖比文字可生動多了
項目如何組件化:
組件化核心:router##
我們在抽象 module 時城舞,module 之間是沒有相互依賴的轩触,是嚴(yán)格解耦的,為了達(dá)到我們復(fù)用的目的家夺。module 之間不能相互依賴脱柱,就沒法調(diào)用別的 module 的代碼了,那么面對業(yè)務(wù)之間的頁面相互調(diào)起秦踪,相互通信這些常見的需求我們該怎么辦褐捻,沒錯就是大伙在上面的圖里面看見的東西 router掸茅。
router 是我們統(tǒng)一制定的模塊間通訊協(xié)議椅邓,router 中我們主要是處理一下幾個問題:
- 模塊之間頁面跳轉(zhuǎn)
- 模塊之間數(shù)據(jù)傳遞
- 模塊初始化處理
router 這東西有現(xiàn)成的,你也可以自己封裝昧狮。使用的思路都是把 router 作為一個組件景馁,所有的業(yè)務(wù) module 都依賴這個 router 組件,當(dāng)然殼app 也是逗鸣,然后我們把需要的模塊間頁面跳轉(zhuǎn)合住,數(shù)據(jù)傳遞绰精,初始化都注冊到 router 中,這里面就體現(xiàn)到我們定義的統(tǒng)一透葛,通用的模塊通訊協(xié)議的重要性了笨使,router 維護(hù)多個集合保存這里關(guān)系,然后我們通過router 就可以實現(xiàn)模塊間的通訊了僚害。
router 的封裝還是挺麻煩的硫椰,要寫好了不容易,現(xiàn)在用的比較多的有:
- 阿里的 ARouter
- 最早出現(xiàn)的 ActivityRouter
- spiny同學(xué)的router這是我的最愛萨蚕,目前不維護(hù)了靶草,思路很棒,并且考慮到了進(jìn)程化的問題岳遥,可惜沒有使用 APT 注解技術(shù)
- 練手的 router
上面我介紹了幾個 router 路由奕翔,基本上不論時自己寫還是用現(xiàn)成的,router 基本上都是上面這幾個的樣子了浩蓉,當(dāng)然了現(xiàn)在好的 router 還是要使用 APT注解技術(shù)來動態(tài)去 router 注冊模塊方法派继,自己寫代碼去注冊的話使用很使用,有些問題不好處理捻艳,比如 router 的靜態(tài)實例要是被回收了互艾,你再 new 一個出來,那么模塊注冊的方法怎么辦讯泣,寫起來太麻煩纫普,還不如 APT 注解來的方便,擴(kuò)展性也好好渠。這里有個ToyBricks_Android項目模塊化解決方案 可以解決 APT不能掃描 arr 包的問題昨稼。
最后說一下,module 間的通訊其實可以分成3種:
- 頁面調(diào)起
- 某種事件的通知
- 直接調(diào)用某些模塊的業(yè)務(wù)方法
頁面調(diào)起現(xiàn)在的 router 都可以很好的完成這個任務(wù)拳锚。
某些事件的通知假栓,比如我切換城市了,通知某些頁面去顯示或是刷新數(shù)據(jù)霍掺,這個根據(jù)業(yè)務(wù)來說影響的范圍會很廣的匾荆,會影響多個業(yè)務(wù)的,因為 module 的復(fù)用性杆烁,我們在 module 中是不能確定會具體影響哪些業(yè)務(wù)module 的牙丽,那么這種場景使用 eventbus/廣播比較合適了。
直接調(diào)用默寫模塊的業(yè)務(wù)方法兔魂,這屬性業(yè)務(wù)模塊間在業(yè)務(wù)上的強耦合了烤芦,這個碰到產(chǎn)品這么設(shè)計你也沒辦法,一般碰到這樣的場景也是會保證相關(guān)的業(yè)務(wù)module 都是會加載的析校,所以呢在定義 router 靈活一些构罗,可以做到調(diào)用指定module 的某些方法
找到另一個說法铜涉,我很喜歡,和我的理念也很接近
出自:Android 架構(gòu)設(shè)計:MVC遂唧、MVP芙代、MVVM和組件化
所謂的組件化,通俗理解就是將一個工程分成各個模塊盖彭,各個模塊之間相互解耦链蕊,可以獨立開發(fā)并編譯成一個獨立的 APP 進(jìn)行調(diào)試,然后又可以將各個模塊組合起來整體構(gòu)成一個完整的 APP谬泌。它的好處是當(dāng)工程比較大的時候滔韵,便于各個開發(fā)者之間分工協(xié)作、同步開發(fā)掌实;被分割出來的模塊又可以在項目之間共享陪蜻,從而達(dá)到復(fù)用的目的。組件化有諸多好處贱鼻,尤其適用于比較大型的項目宴卖。
各個模塊之間如何進(jìn)行數(shù)據(jù)共享和數(shù)據(jù)通信?我們可以把需要共享的數(shù)據(jù)劃分成一個單獨的模塊來放置公共數(shù)據(jù)邻悬。各個模塊之間的數(shù)據(jù)通信症昏,我們可以使用阿里的 ARouter 進(jìn)行頁面的跳轉(zhuǎn),使用封裝之后的 RxJava 作為 EventBus 進(jìn)行全局的數(shù)據(jù)通信父丰。
router 我不想說太多肝谭,也說不好,這部分大伙看我最后的鏈接吧蛾扇,或是看看上面4個路由也可以攘烛,不論如何實現(xiàn),router 是為了給 module 模塊搭建一個通訊的中間平臺镀首,目的就是這樣坟漱。仔細(xì)的大家多看吧,這里我也是看別人的更哄。
我再逼逼一下芋齿,module 和 library 我們盡量不要提供源代碼的方式提供依賴,這不符合我們復(fù)用的目的成翩,到時候你發(fā)布幾個影子功能或是別的 app觅捆,那么你使用源代碼依賴方式的 module 和 library 你怎么提供維護(hù),所以盡量使用 arr 和 jar 的方式捕传。我們可以把一些定位相近library 打包成一個 module 也是不錯的惠拭。
我們一定要熟悉gradle的使用,在組件化中我們會大量的使用 gradle 提供各種資源加載的配置和環(huán)境配置
組件化最核心的目的就是代碼的高可復(fù)用和高可維護(hù)和高可擴(kuò)展性能庸论,其他的優(yōu)點都是屬于連帶性質(zhì)的职辅,我們要先把握住核心點學(xué)習(xí),其他的都不是主要聂示,有時間再看
組件化碰到的問題
1. 子模塊單獨編譯測試
在做組件化開發(fā)時域携,我們測試 module 庫都是把 module 單獨達(dá)成 apk 文件,在發(fā)布module時 提供 library 供外界依賴鱼喉,這都是通過配置 module 的 gradle 的編譯模式實現(xiàn)的
首先在子模塊build.gradle中定義常量秀鞭,來標(biāo)示模塊目前是否處于開發(fā)模式
def isDebug = true
在子模塊的build.gradle中進(jìn)行模式配置。debug模式下編譯成獨立app扛禽,release模式下編譯成library锋边。
if (isDebug.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
兩種模式下模塊AndroidManifest.xml文件是有差別的。作為獨立運行的app编曼,有自己的Application豆巨,要加Launcher的入口intent,作為library不需要掐场。這個問題很好解決往扔,寫兩個不同的AndroidManifest.xml即可,并在gradle中進(jìn)行配置熊户。
在 gradle 腳本中配置
android {
sourceSets {
main {
if(isDebug.toBoolean()) {
manifest.srcFile 'src/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/release/AndroidManifest.xml'
}
}
}
}
2. sdk和第三方庫的版本一致性
不同module依賴sdk版本不一致萍膛,會因兼容性問題導(dǎo)致編譯問題。
不同module引用了同一個第三方庫的不同版本嚷堡,并且這個庫沒有做到向前兼容蝗罗,就有可能出現(xiàn)方法找不到、參數(shù)不對應(yīng)等問題蝌戒。
所以有必要統(tǒng)一整個project的依賴版本绿饵。
在最外層build.gradle中定義的常量能被整個project的build.gradle文件引用,統(tǒng)一的版本定義可以放在這里瓶颠。
ext {
android_compileSdkVersion = 25
android_buildToolsVersion = '25.0.2'
android_minSdkVersion = 21
android_targetSdkVersion = 25
lib_appcompat = 'com.android.support:appcompat-v7:25.1.1'
lib_picasso = 'com.squareup.picasso:picasso:2.5.2'
lib_gson = 'com.google.code.gson:gson:2.6.1'
}
我沒試過 arr資源的 module 是否還可以使用這種方式
3. 資源id沖突
android 中 module的資源文件最后都是會合并到主項目中的拟赊,資源文件的 id 最終和 moudle 是的 id 時不一樣的,所以這就會出現(xiàn)資源重名的問題粹淋,解決這個問題吸祟,我們的做法就是module 資源加一個統(tǒng)一的前綴
andorid{
...
buildTypes{
...
}
resourcePrefix "moudle_prefix"
}
但是注意 res 文件夾下的文件可以用 gradle 腳本加前綴,但是圖片資源不行桃移,圖片資源我們還是需要在命名時自己添加前綴
4. application初始化的問題
子模塊作為application時屋匕,有一些初始化的工作需要在Application.onCreate時進(jìn)行。而作為library時借杰,調(diào)不到這個onCreate过吻。所以自己寫一個靜態(tài)方法,供主工程的Application調(diào)用。
public class ApplicationA extends Application {
@Override public void onCreate() {
super.onCreate();
//給底層library設(shè)置context
AppContext.init(getApplicationContext());
}
/**
* 作為library時需要初始化的內(nèi)容
*/
public static void onCreateAsLibrary() {
//給FunctionBus傳入接口的實例
FunctionBus.setFunction(new FunctionA() {
@Override public String getData(String key) {
return "xixi";
}
});
}
}
主工程的Application onCreate時記得初始化子模塊纤虽。
public class MainApplication extends Application {
@Override public void onCreate() {
super.onCreate();
AppContext.init(getApplicationContext());
ApplicationA.onCreateAsLibrary();
ApplicationB.onCreateAsLibrary();
}
}
除了提供方法在殼工程里面調(diào)用乳绕,還可以結(jié)合使用了 APT 技術(shù)的 router 來做,使用注解逼纸,就不用我們自己去調(diào)用了洋措,徹底解耦
5. library依賴問題
先說一個問題,在組件化工程模型圖中杰刽,多媒體組件和Common組件都依賴了日志組件菠发,而A業(yè)務(wù)組件有同時依賴了多媒體組件和Common組件,這時候就會有人問贺嫂,你這樣搞豈不是日志組件要被重復(fù)依賴了滓鸠,而且Common組件也被每一個業(yè)務(wù)組件依賴了,這樣不出問題嗎第喳?
其實大家完全沒有必要擔(dān)心這個問題糜俗,如果真有重復(fù)依賴的問題,在你編譯打包的時候就會報錯墩弯,如果你還是不相信的話可以反編譯下最后打包出來的APP吩跋,看看里面的代碼你就知道了。組件只是我們在代碼開發(fā)階段中為了方便叫的一個術(shù)語渔工,在組件被打包進(jìn)APP的時候是沒有這個概念的锌钮,這些組件最后都會被打包成arr包,然后被app殼工程所依賴引矩,在構(gòu)建APP的過程中Gradle會自動將重復(fù)的arr包排除梁丘,APP中也就不會存在相同的代碼了;
但是雖然組件是不會重復(fù)了旺韭,但是我們還是要考慮另一個情況氛谜,我們在build.gradle中compile的第三方庫,例如AndroidSupport庫經(jīng)常會被一些開源的控件所依賴区端,而我們自己一定也會compile AndroidSupport庫 值漫,這就會造成第三方包和我們自己的包存在重復(fù)加載,解決辦法就是找出那個多出來的庫织盼,并將多出來的庫給排除掉杨何,而且Gradle也是支持這樣做的,分別有兩種方式:根據(jù)組件名排除或者根據(jù)包名排除沥邻,下面以排除support-v4庫為例:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile("com.jude:easyrecyclerview:$rootProject.easyRecyclerVersion") {
exlude module: 'support-v4'//根據(jù)組件名排除
exlude group: 'android.support.v4'//根據(jù)包名排除
}
}
library重復(fù)依賴的問題算是都解決了危虱,但是我們在開發(fā)項目的時候會依賴很多開源庫,而這些庫每個組件都需要用到唐全,要是每個組件都去依賴一遍也是很麻煩的埃跷,尤其是給這些庫升級的時候,為了方便我們統(tǒng)一管理第三方庫,我們將給給整個工程提供統(tǒng)一的依賴第三方庫的入口弥雹,前面介紹的Common庫的作用之一就是統(tǒng)一依賴開源庫垃帅,因為其他業(yè)務(wù)組件都依賴了Common庫,所以這些業(yè)務(wù)組件也就間接依賴了Common所依賴的開源庫缅糟。
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
//Android Support
compile "com.android.support:appcompat-v7:$rootProject.supportLibraryVersion"
compile "com.android.support:design:$rootProject.supportLibraryVersion"
compile "com.android.support:percent:$rootProject.supportLibraryVersion"
//網(wǎng)絡(luò)請求相關(guān)
compile "com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion"
compile "com.squareup.retrofit2:retrofit-mock:$rootProject.retrofitVersion"
compile "com.github.franmontiel:PersistentCookieJar:$rootProject.cookieVersion"
//穩(wěn)定的
compile "com.github.bumptech.glide:glide:$rootProject.glideVersion"
compile "com.orhanobut:logger:$rootProject.loggerVersion"
compile "org.greenrobot:eventbus:$rootProject.eventbusVersion"
compile "com.google.code.gson:gson:$rootProject.gsonVersion"
compile "com.github.chrisbanes:PhotoView:$rootProject.photoViewVersion"
compile "com.jude:easyrecyclerview:$rootProject.easyRecyclerVersion"
compile "com.github.GrenderG:Toasty:$rootProject.toastyVersion"
//router
compile "com.github.mzule.activityrouter:activityrouter:$rootProject.routerVersion"
}
6. module不同業(yè)務(wù)環(huán)境使用不同代碼
我們做項目至少會有測試和線上2套環(huán)境吧挺智,組件化讓我們開始重視 gradle祷愉,通過 gradle 配置我們可以減少很多代碼的書寫的窗宦,切換環(huán)境我們也是可以用 gradle 實現(xiàn)的,在不通過的環(huán)境下注冊不同的代碼文件二鳄,看下面這張圖
我們有 debug 和 release2個環(huán)境赴涵,里面放的是不同環(huán)境執(zhí)行的代碼,main 里面是跟環(huán)境切換無關(guān)的代碼部分订讼,我我們這樣設(shè)置 gradle 就可以了
android {
// ...
sourceSets {
debug {
java.srcDirs = ['src/main/java', 'src/debug/java']
}
release {
java.srcDirs = ['src/main/java', 'src/release/java']
}
}
}
此外在發(fā)布該 library 時髓窜,需要指定一些設(shè)置,如下:
android {
// ...
defaultConfig {
// ...
defaultPublishConfig 'release'
publishNonDefault true
}
}
說明:
- defaultPublishConfig 'release'欺殿,默認(rèn) library 只會生產(chǎn) release 下的版本寄纵,此版本將會被所有項目使用,通過defaultPublishConfig可以控制默認(rèn)生產(chǎn)哪個版本的庫脖苏。
- publishNonDefault true程拭,默認(rèn)情況下不能生產(chǎn)所有版本的 library,通過設(shè)置publishNonDefault為true棍潘,可以同時生產(chǎn)所有版本的 library恃鞋。
業(yè)務(wù)組件 module 依賴不同的基礎(chǔ)組件生產(chǎn)的 library,如下:
dependencies {
// ...
debugCompile project(path: ':baselibrary', configuration: "debug")
releaseCompile project(path: ':baselibrary', configuration: "release")
}
在使用通過這樣的配置腳本解決了多個 APK 包依賴同一組件生產(chǎn)的不同的 library亦歉,最終得到我們需要的開發(fā)/測試/生產(chǎn) APK 包恤浪。
合并多個 module 到一個文件夾
studio 中的 module 我們在引用時都是用,項目名 + :冒號來表示的
implementation project(':basecomponents')
注意這只是表示我們要引用這個名字的 module 了肴楷,而這個 module 的地址這里我們不管
那么就可以理解為 module 的地址可以隨我們?nèi)我馀渲盟桑敲丛谀睦锱渲?module 的地址呢,答案就是在 setting.gradle 文件里赛蔫,我們給 ':basecomponents' 這個 module 指定他的地址就行
比如我們想新建一個名字為 components 的文件夾存放我們的組件 module 砂客,組件我們給2個 ( basecomponents,aaa ),然后我們在 setting.gradle 里指定每個項目的文件路徑
include ':app', ':basecomponents', ':aaa'
project(':basecomponents').projectDir = new File( 'components/basecomponents' )
project(':aaa').projectDir = new File( 'components/aaa' )
一個好的組件化文檔是必須的
組件化是 android 開發(fā)步入新時代的未來濒募,是代碼膨脹鞭盟,支持快速開發(fā)的必然,一個好的組件化文檔在現(xiàn)今來看也是必須的了
下面貼個圖
組件化的坑
組件化是好瑰剃,但是坑也是不少齿诉,不好填,尤其是 databinding,dagger粤剧,bufferkinft歇竟,這是源于 studio 編譯的問題。
studio 中 module 雖然時在代碼上獨立于殼工程的抵恋,但是在編譯時最后還是要合并到殼工程中的焕议,要不怎么達(dá)成一個 APK 文件,要是多個 APK 文件把不成了插件化了嘛弧关,插件化坑更多啊盅安。合并 module 到殼工程就會產(chǎn)生一個根本問題,module 的 R 文件數(shù)值改變了世囊。module 的 R文件數(shù)據(jù)不是固定的别瞭,只有殼工程的 R 文件才是常量值,時不變的株憾,module 的 R 文件數(shù)值在把 modul 的資源合并到殼工程后才會確定下來蝙寨,那么這就對依靠編譯時注解的技術(shù)造成了難題,你指定的 R 路徑最后找不到嗤瞎,并且據(jù)說這里面還涉及注解的 final 墙歪,不了解,看到有人這么說贝奇,所以大家在開發(fā)組件化時對于帶注解技術(shù)的框架要多注意虹菲,有坑要多看才能爬過去
組件化文章:
Android 模塊化探索與實踐 安居客的時間案例,對概念的解釋非常到位弃秆,適合初學(xué)者和概念混亂的同學(xué)看届惋,特別是有提供詳細(xì)的 demo 哦
關(guān)于Android模塊化我有一些話不知當(dāng)講不 這是我目前看到的最貼近實際的好文了,絕對值得一看的
Android組件化方案這篇文章講的最好菠赚,還設(shè)計大量 gradle 配置的思考
ToyBricks_Android項目模塊化解決方案使用 apt 注解技術(shù)解耦
一次 Android 項目組件化 介紹了不少實際 gradle 配置使用
android組件化方案脑豹,讓團(tuán)隊開發(fā)更有效率借鑒 retrofit 的方式聲明
router 接口,時個思路衡查,但是沒有達(dá)到徹底解耦瘩欺,可以參考下。蘑菇街 App 的組件化之路這和講 IOS 的
優(yōu)秀的組件化方案
優(yōu)秀的router 路由器設(shè)計
gradle學(xué)習(xí)文章
學(xué)習(xí) gradwle 的入門系列俱饿,翻譯自官方文檔,適合入口看塌忽,學(xué)習(xí)各種概念
- Gradle for Android 第一篇( 從 Gradle 和 AS 開始 )
- Gradle for Android 第二篇( Build.gradle入門 )
- Gradle for Android 第三篇( 依賴管理 )
- Gradle for Android 第四篇( 構(gòu)建變體 )
- Gradle for Android 第五篇( 多模塊構(gòu)建 )
- Gradle for Android 第六篇( 測試)
- Gradle for Android 第七篇( Groovy入門 )
gradle 各種常用使用
- Gradle 使用配置總結(jié)
- android gradle使用詳解
- 關(guān)于Gradle配置的小結(jié)
- android gradle自動化打包方案完整總結(jié)
- Android Gradle 常用使用場景實現(xiàn)方式的總結(jié)
- Android Gradle高級用法拍埠,動態(tài)編譯技術(shù):Plugin Transform Javassist操作Class文件
飛雪無情的 gradle 教程
吳小龍的gradle 的教程
- Gradle for Android(一)基本配置、依賴管理
- Gradle for Android(二)全局設(shè)置土居、自定義BuildConfig枣购、混淆
- Gradle for Android(三)多渠道打包嬉探、配置簽名信息
其他