談?wù)勎业睦斫?組件化/模塊化

今天來回味下組件化和模塊化屋休,這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ì)看看,圖比文字可生動多了

modularization.png
modules.png
20170118062508842.png
20170118064804889.png
20161202165647074.png

項目如何組件化:

20170522211601227.png
3688153-dba93d79b7426568.png

組件化核心: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.png

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)境下注冊不同的代碼文件二鳄,看下面這張圖

1281144-3d9c01d6ac6d30fe.png

我們有 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' )
Snip20180905_2.png

一個好的組件化文檔是必須的

組件化是 android 開發(fā)步入新時代的未來濒募,是代碼膨脹鞭盟,支持快速開發(fā)的必然,一個好的組件化文檔在現(xiàn)今來看也是必須的了

下面貼個圖

20160311130348_213.jpg
20160311130349_276.jpg

組件化的坑

組件化是好瑰剃,但是坑也是不少齿诉,不好填,尤其是 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ù)的框架要多注意虹菲,有坑要多看才能爬過去

組件化文章:


優(yōu)秀的組件化方案


優(yōu)秀的router 路由器設(shè)計


gradle學(xué)習(xí)文章

學(xué)習(xí) gradwle 的入門系列俱饿,翻譯自官方文檔,適合入口看塌忽,學(xué)習(xí)各種概念

gradle 各種常用使用

飛雪無情的 gradle 教程

吳小龍的gradle 的教程

其他

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市棉圈,隨后出現(xiàn)的幾起案子涩堤,更是在濱河造成了極大的恐慌,老刑警劉巖分瘾,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胎围,死亡現(xiàn)場離奇詭異,居然都是意外死亡德召,警方通過查閱死者的電腦和手機白魂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來氏捞,“玉大人碧聪,你說我怎么就攤上這事冒版∫壕ィ” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵辞嗡,是天一觀的道長捆等。 經(jīng)常有香客問我,道長续室,這世上最難降的妖魔是什么栋烤? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮挺狰,結(jié)果婚禮上明郭,老公的妹妹穿的比我還像新娘。我一直安慰自己丰泊,他們只是感情好薯定,可當(dāng)我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瞳购,像睡著了一般话侄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上学赛,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天年堆,我揣著相機與錄音,去河邊找鬼盏浇。 笑死变丧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的绢掰。 我是一名探鬼主播痒蓬,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼译蒂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了谊却?” 一聲冷哼從身側(cè)響起柔昼,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎炎辨,沒想到半個月后捕透,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡碴萧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年乙嘀,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片破喻。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡虎谢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出曹质,到底是詐尸還是另有隱情婴噩,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布羽德,位于F島的核電站几莽,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏宅静。R本人自食惡果不足惜章蚣,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望姨夹。 院中可真熱鬧纤垂,春花似錦、人聲如沸磷账。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽够颠。三九已至熙侍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間履磨,已是汗流浹背蛉抓。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留剃诅,地道東北人巷送。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像矛辕,于是被迫代替她去往敵國和親笑跛。 傳聞我的和親對象是個殘疾皇子付魔,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,162評論 25 707
  • 不怕跌倒,所以飛翔 組件化開發(fā) 參考資源 Android組件化方案 為什么要組件化開發(fā) 解決問題 實際業(yè)務(wù)變化非常...
    筆墨Android閱讀 2,984評論 0 0
  • 這一生有你相伴,我不期待來世陈哑,來世太遙遠(yuǎn)妻坝,我只要這一生有你相伴! 這一生有你相伴惊窖,是我們等候了無數(shù)次輪回的終結(jié)刽宪,是...
    清風(fēng)過山崗閱讀 541評論 0 0
  • 【感恩張戰(zhàn)濤老師圣拄,治好媽媽十幾年的頸椎病~】我的媽媽,因為常年勞累毁欣,頸椎庇谆、腰椎都不好,這兩年更甚署辉,經(jīng)常性頭暈族铆,雙手...
    d01aee4569f8閱讀 426評論 0 3
  • %~哎,今天好像可以查公務(wù)員考試的成績啦哭尝,你查了沒有啊剖煌! &~我還沒有噶材鹦,你考的怎么樣啊耕姊!應(yīng)該可以吧桶唐,你的條件,應(yīng)...
    跳梁貴妃閱讀 450評論 0 2