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

今天來回味下組件化和模塊化,這2種說法時(shí)一回事,當(dāng)然還是有區(qū)別的,下面再詳細(xì)說,其實(shí)很簡單,只是設(shè)計(jì)范圍的不同,也都是約定俗成的東西。為了方便我下面都說組件化了

到現(xiàn)在組件化真的不是什么新鮮東西了,大公司都用的滾瓜爛熟,龍飛鳳舞了,也就是現(xiàn)在部分中型項(xiàng)目和小項(xiàng)目在組件化的路上努力。所以同志們,組件化沒玩過的,不熟悉的趕緊搞起來,說一點(diǎn),你不會(huì)組件化,發(fā)布影子工程那么對(duì)你來說就是個(gè)噩夢(mèng)。從本質(zhì)上來講任何技術(shù)進(jìn)步都是在現(xiàn)實(shí)需求的逼迫下抓耳撓腮,耗盡無數(shù)頭發(fā)才想出來的。哈哈,這里說個(gè)笑話罷了。所以呢組件化這個(gè)東西出來這么久了,頁發(fā)展了這么久了,用的人越來越多,那肯定是對(duì)我們顯示開發(fā)大有裨益的,下伙伴們不會(huì),不熟悉抓緊啦,要不面試問你你怎么回答呢!

下面來正式說說組件化

組件化這個(gè)東西其實(shí)并不復(fù)雜,他就是種思路,本質(zhì)上是一種 app 架構(gòu)思路,說穿了很簡單的,難在組件化改造的時(shí)候,真正寫起代碼會(huì)出現(xiàn)不少棘手的問題,當(dāng)然這些坑基本前人都趟完了,這里我主要時(shí)記錄下,要是你看到熟悉的部分,請(qǐng)不要罵我啊,畢竟都是前輩們的東西啊。

這里補(bǔ)充一下,組件化時(shí)一種 app 架構(gòu),他的發(fā)展也是沿著正常的技術(shù)發(fā)展脈絡(luò)來的,也是為了以追求高復(fù)用,高可維護(hù)性的目的的代碼封裝,區(qū)別是組件化是對(duì)整個(gè) app 的再次封裝。

廢話了這么多,那么什么是組件化呢,各位看官想不要著急,在詳細(xì)說組件化之前,我們要搞懂2個(gè)概念,就是上面說的組件和模塊。

首先組件和模塊都不是官方規(guī)定的,都是這些技術(shù)發(fā)展下來大家約定俗成的概念,其實(shí)很簡單,一說就明白

  • 模塊:android 中的模塊就是業(yè)務(wù)模塊,單指業(yè)務(wù),是按照業(yè)務(wù)對(duì) app 進(jìn)行拆分,比如說訂單我們搞成一個(gè)模塊,個(gè)人中心我們搞成一個(gè)模塊,視頻,音頻這些都搞成模塊,在app中的體現(xiàn)就是 一個(gè)個(gè)module,module 的中文意思也是模塊,這不準(zhǔn)這就是 google 對(duì)我們的暗示呢。模塊化的目的時(shí)為了搭積木,隨便拿幾個(gè)模塊module 出來就可以誰誰便便的上線一個(gè) app,你還別說現(xiàn)在影子 app 的需求很旺盛,你去看看大公司的項(xiàng)目那個(gè)不是一堆影子工程,頭條還搞出一個(gè)頭條視頻的馬甲呢,這其實(shí)就是把視頻 module 拿出來,加上一個(gè)啟動(dòng)頁。這樣的例子是比比皆是的,要不說不會(huì)組件化影子工程對(duì)你就是噩夢(mèng)呢,哈哈,到時(shí)候維護(hù)那是想也別想了,代碼你要搞多少份啊。

  • 組件:這個(gè)一樣簡單啊,說穿了就是我們平時(shí)干的事,對(duì)功能的封裝,這就是組件,一個(gè)功能就是一個(gè)組件,IO,數(shù)據(jù)庫,網(wǎng)絡(luò)等等這些功能都是組件,這么說你就明白了吧。既然這樣那為毛線我們還要搞出來這個(gè)一個(gè)組件的概念,當(dāng)然了任何事都是有其意義的,因?yàn)榻M件對(duì)功能代碼的封裝有個(gè)很高了明確的要求:一處封裝,處處使用。要我們把維護(hù)性,復(fù)用性,擴(kuò)展性,性能做到極致,因?yàn)檫@樣才能真正做到一處封裝,處處使用。當(dāng)然組件的范圍現(xiàn)在也是覆蓋的很廣的,app 中的一切都是組件,基本上我們分為:基礎(chǔ)功能組件,通用UI組件,基礎(chǔ)業(yè)務(wù)組件。

以上我談了下我自己對(duì)于模塊化,組件化的理解,是目前開發(fā)中對(duì)于模塊和組件的理解。在模塊化和組件化的發(fā)展中概念也是有些調(diào)整變化的,大家只要看現(xiàn)在時(shí)什么樣子就好了,深入學(xué)習(xí)的話有興趣可以看看組件化,模塊化的發(fā)展歷程。

我認(rèn)為 Android 模塊化探索與實(shí)踐 對(duì)于模塊化,組件化概念的解釋時(shí)最優(yōu)秀的。

組件化和模塊化在現(xiàn)在看是一回事了,如果把一個(gè)項(xiàng)目看成是袋中的組合的話,那么模塊就是體積最大的哪些袋子,組件就是體積小的袋子,大的袋子是最直接可被外接觀測(cè)和接觸的袋子,大的袋子也是用小的袋子組成的,一個(gè)不太恰當(dāng)?shù)谋扔靼?,模塊和組件就是這樣的關(guān)系,是我們對(duì)業(yè)務(wù)和功能拆分,封裝的理解。

好了正式開始介紹了組件化啦

組件化在工程表現(xiàn)上就是我們把 app 按照其業(yè)務(wù)的不同,劃分為不同的 module模塊,把各種功能封裝成一個(gè)個(gè) library,module 之間時(shí)嚴(yán)格禁止橫向依賴的,要不怎么單獨(dú)使用呢,我不能為了用一個(gè) module,把相關(guān)的module 都帶上吧,要是這么 module 還有依賴的module 呢,這樣談復(fù)用性就是扯淡了。

主 app 就是我們常說的殼工程依賴這些 module,library 由需求的 module 依賴,但是要考慮library 版本的問題,隨著業(yè)務(wù)和功能的擴(kuò)展,library 的數(shù)量也是巨大的,微信在組件化拆分時(shí)據(jù)說拆分出80多個(gè) module,可見 library 也是少不了的。

module 和 library 多數(shù)時(shí)候我們時(shí)提供arr 和 jar 來給殼工程引用的,arr 和 jar 在編譯時(shí)是不會(huì)再編譯的,只會(huì)檢查版本,保留一個(gè)最新的版本,既提高了 app 的編譯速度,頁提供一種資源沖突解決方式。

下面我方一些圖來描述一下組件化,大伙仔細(xì)看看,圖比文字可生動(dòng)多了

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

項(xiàng)目如何組件化:

20170522211601227.png
3688153-dba93d79b7426568.png

組件化核心:router##

我們?cè)诔橄?module 時(shí),module 之間是沒有相互依賴的,是嚴(yán)格解耦的,為了達(dá)到我們復(fù)用的目的。module 之間不能相互依賴,就沒法調(diào)用別的 module 的代碼了,那么面對(duì)業(yè)務(wù)之間的頁面相互調(diào)起,相互通信這些常見的需求我們?cè)撛趺崔k,沒錯(cuò)就是大伙在上面的圖里面看見的東西 router。

router 是我們統(tǒng)一制定的模塊間通訊協(xié)議,router 中我們主要是處理一下幾個(gè)問題:

  • 模塊之間頁面跳轉(zhuǎn)
  • 模塊之間數(shù)據(jù)傳遞
  • 模塊初始化處理
router.png

router 這東西有現(xiàn)成的,你也可以自己封裝。使用的思路都是把 router 作為一個(gè)組件,所有的業(yè)務(wù) module 都依賴這個(gè) router 組件,當(dāng)然殼app 也是,然后我們把需要的模塊間頁面跳轉(zhuǎn),數(shù)據(jù)傳遞,初始化都注冊(cè)到 router 中,這里面就體現(xiàn)到我們定義的統(tǒng)一,通用的模塊通訊協(xié)議的重要性了,router 維護(hù)多個(gè)集合保存這里關(guān)系,然后我們通過router 就可以實(shí)現(xiàn)模塊間的通訊了。

router 的封裝還是挺麻煩的,要寫好了不容易,現(xiàn)在用的比較多的有:

  • 阿里的 ARouter
  • 最早出現(xiàn)的 ActivityRouter
  • spiny同學(xué)的router這是我的最愛,目前不維護(hù)了,思路很棒,并且考慮到了進(jìn)程化的問題,可惜沒有使用 APT 注解技術(shù)
  • 練手的 router

上面我介紹了幾個(gè) router 路由,基本上不論時(shí)自己寫還是用現(xiàn)成的,router 基本上都是上面這幾個(gè)的樣子了,當(dāng)然了現(xiàn)在好的 router 還是要使用 APT注解技術(shù)來動(dòng)態(tài)去 router 注冊(cè)模塊方法,自己寫代碼去注冊(cè)的話使用很使用,有些問題不好處理,比如 router 的靜態(tài)實(shí)例要是被回收了,你再 new 一個(gè)出來,那么模塊注冊(cè)的方法怎么辦,寫起來太麻煩,還不如 APT 注解來的方便,擴(kuò)展性也好。這里有個(gè)ToyBricks_Android項(xiàng)目模塊化解決方案 可以解決 APT不能掃描 arr 包的問題。

最后說一下,module 間的通訊其實(shí)可以分成3種:

  • 頁面調(diào)起
  • 某種事件的通知
  • 直接調(diào)用某些模塊的業(yè)務(wù)方法

頁面調(diào)起現(xiàn)在的 router 都可以很好的完成這個(gè)任務(wù)。

某些事件的通知,比如我切換城市了,通知某些頁面去顯示或是刷新數(shù)據(jù),這個(gè)根據(jù)業(yè)務(wù)來說影響的范圍會(huì)很廣的,會(huì)影響多個(gè)業(yè)務(wù)的,因?yàn)?module 的復(fù)用性,我們?cè)?module 中是不能確定會(huì)具體影響哪些業(yè)務(wù)module 的,那么這種場(chǎng)景使用 eventbus/廣播比較合適了。

直接調(diào)用默寫模塊的業(yè)務(wù)方法,這屬性業(yè)務(wù)模塊間在業(yè)務(wù)上的強(qiáng)耦合了,這個(gè)碰到產(chǎn)品這么設(shè)計(jì)你也沒辦法,一般碰到這樣的場(chǎng)景也是會(huì)保證相關(guān)的業(yè)務(wù)module 都是會(huì)加載的,所以呢在定義 router 靈活一些,可以做到調(diào)用指定module 的某些方法

找到另一個(gè)說法,我很喜歡,和我的理念也很接近
出自:Android 架構(gòu)設(shè)計(jì):MVC、MVP、MVVM和組件化

所謂的組件化,通俗理解就是將一個(gè)工程分成各個(gè)模塊,各個(gè)模塊之間相互解耦,可以獨(dú)立開發(fā)并編譯成一個(gè)獨(dú)立的 APP 進(jìn)行調(diào)試,然后又可以將各個(gè)模塊組合起來整體構(gòu)成一個(gè)完整的 APP。它的好處是當(dāng)工程比較大的時(shí)候,便于各個(gè)開發(fā)者之間分工協(xié)作、同步開發(fā);被分割出來的模塊又可以在項(xiàng)目之間共享,從而達(dá)到復(fù)用的目的。組件化有諸多好處,尤其適用于比較大型的項(xiàng)目。

各個(gè)模塊之間如何進(jìn)行數(shù)據(jù)共享和數(shù)據(jù)通信?我們可以把需要共享的數(shù)據(jù)劃分成一個(gè)單獨(dú)的模塊來放置公共數(shù)據(jù)。各個(gè)模塊之間的數(shù)據(jù)通信,我們可以使用阿里的 ARouter 進(jìn)行頁面的跳轉(zhuǎn),使用封裝之后的 RxJava 作為 EventBus 進(jìn)行全局的數(shù)據(jù)通信。


router 我不想說太多,也說不好,這部分大伙看我最后的鏈接吧,或是看看上面4個(gè)路由也可以,不論如何實(shí)現(xiàn),router 是為了給 module 模塊搭建一個(gè)通訊的中間平臺(tái),目的就是這樣。仔細(xì)的大家多看吧,這里我也是看別人的。

我再逼逼一下,module 和 library 我們盡量不要提供源代碼的方式提供依賴,這不符合我們復(fù)用的目的,到時(shí)候你發(fā)布幾個(gè)影子功能或是別的 app,那么你使用源代碼依賴方式的 module 和 library 你怎么提供維護(hù),所以盡量使用 arr 和 jar 的方式。我們可以把一些定位相近library 打包成一個(gè) module 也是不錯(cuò)的。

我們一定要熟悉gradle的使用,在組件化中我們會(huì)大量的使用 gradle 提供各種資源加載的配置和環(huán)境配置

組件化最核心的目的就是代碼的高可復(fù)用和高可維護(hù)和高可擴(kuò)展性能,其他的優(yōu)點(diǎn)都是屬于連帶性質(zhì)的,我們要先把握住核心點(diǎn)學(xué)習(xí),其他的都不是主要,有時(shí)間再看


組件化碰到的問題

1. 子模塊單獨(dú)編譯測(cè)試

在做組件化開發(fā)時(shí),我們測(cè)試 module 庫都是把 module 單獨(dú)達(dá)成 apk 文件,在發(fā)布module時(shí) 提供 library 供外界依賴,這都是通過配置 module 的 gradle 的編譯模式實(shí)現(xiàn)的

首先在子模塊build.gradle中定義常量,來標(biāo)示模塊目前是否處于開發(fā)模式

def isDebug = true

在子模塊的build.gradle中進(jìn)行模式配置。debug模式下編譯成獨(dú)立app,release模式下編譯成library。

if (isDebug.toBoolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}

兩種模式下模塊AndroidManifest.xml文件是有差別的。作為獨(dú)立運(yùn)行的app,有自己的Application,要加Launcher的入口intent,作為library不需要。這個(gè)問題很好解決,寫兩個(gè)不同的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版本不一致,會(huì)因兼容性問題導(dǎo)致編譯問題。
不同module引用了同一個(gè)第三方庫的不同版本,并且這個(gè)庫沒有做到向前兼容,就有可能出現(xiàn)方法找不到、參數(shù)不對(duì)應(yīng)等問題。
所以有必要統(tǒng)一整個(gè)project的依賴版本。

在最外層build.gradle中定義的常量能被整個(gè)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的資源文件最后都是會(huì)合并到主項(xiàng)目中的,資源文件的 id 最終和 moudle 是的 id 時(shí)不一樣的,所以這就會(huì)出現(xiàn)資源重名的問題,解決這個(gè)問題,我們的做法就是module 資源加一個(gè)統(tǒng)一的前綴

andorid{
    ...

    buildTypes{
        ...
    }

    resourcePrefix "moudle_prefix"

}

但是注意 res 文件夾下的文件可以用 gradle 腳本加前綴,但是圖片資源不行,圖片資源我們還是需要在命名時(shí)自己添加前綴

4. application初始化的問題

子模塊作為application時(shí),有一些初始化的工作需要在Application.onCreate時(shí)進(jìn)行。而作為library時(shí),調(diào)不到這個(gè)onCreate。所以自己寫一個(gè)靜態(tài)方法,供主工程的Application調(diào)用。

public class ApplicationA extends Application {

@Override public void onCreate() {
  super.onCreate();
  //給底層library設(shè)置context
  AppContext.init(getApplicationContext());
}
  /**
   * 作為library時(shí)需要初始化的內(nèi)容
   */
  public static void onCreateAsLibrary() {
    //給FunctionBus傳入接口的實(shí)例
    FunctionBus.setFunction(new FunctionA() {
      @Override public String getData(String key) {
        return "xixi";
      }
    });
  }
}
主工程的Application onCreate時(shí)記得初始化子模塊。

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依賴問題

先說一個(gè)問題,在組件化工程模型圖中,多媒體組件和Common組件都依賴了日志組件,而A業(yè)務(wù)組件有同時(shí)依賴了多媒體組件和Common組件,這時(shí)候就會(huì)有人問,你這樣搞豈不是日志組件要被重復(fù)依賴了,而且Common組件也被每一個(gè)業(yè)務(wù)組件依賴了,這樣不出問題嗎?

其實(shí)大家完全沒有必要擔(dān)心這個(gè)問題,如果真有重復(fù)依賴的問題,在你編譯打包的時(shí)候就會(huì)報(bào)錯(cuò),如果你還是不相信的話可以反編譯下最后打包出來的APP,看看里面的代碼你就知道了。組件只是我們?cè)诖a開發(fā)階段中為了方便叫的一個(gè)術(shù)語,在組件被打包進(jìn)APP的時(shí)候是沒有這個(gè)概念的,這些組件最后都會(huì)被打包成arr包,然后被app殼工程所依賴,在構(gòu)建APP的過程中Gradle會(huì)自動(dòng)將重復(fù)的arr包排除,APP中也就不會(huì)存在相同的代碼了;

但是雖然組件是不會(huì)重復(fù)了,但是我們還是要考慮另一個(gè)情況,我們?cè)赽uild.gradle中compile的第三方庫,例如AndroidSupport庫經(jīng)常會(huì)被一些開源的控件所依賴,而我們自己一定也會(huì)compile AndroidSupport庫 ,這就會(huì)造成第三方包和我們自己的包存在重復(fù)加載,解決辦法就是找出那個(gè)多出來的庫,并將多出來的庫給排除掉,而且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ù)依賴的問題算是都解決了,但是我們?cè)陂_發(fā)項(xiàng)目的時(shí)候會(huì)依賴很多開源庫,而這些庫每個(gè)組件都需要用到,要是每個(gè)組件都去依賴一遍也是很麻煩的,尤其是給這些庫升級(jí)的時(shí)候,為了方便我們統(tǒng)一管理第三方庫,我們將給給整個(gè)工程提供統(tǒng)一的依賴第三方庫的入口,前面介紹的Common庫的作用之一就是統(tǒng)一依賴開源庫,因?yàn)槠渌麡I(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ò)請(qǐng)求相關(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)境使用不同代碼

我們做項(xiàng)目至少會(huì)有測(cè)試和線上2套環(huán)境吧,組件化讓我們開始重視 gradle,通過 gradle 配置我們可以減少很多代碼的書寫的,切換環(huán)境我們也是可以用 gradle 實(shí)現(xiàn)的,在不通過的環(huán)境下注冊(cè)不同的代碼文件,看下面這張圖

1281144-3d9c01d6ac6d30fe.png

我們有 debug 和 release2個(gè)環(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í),需要指定一些設(shè)置,如下:

android {
    // ...
    defaultConfig {
        // ...
        defaultPublishConfig 'release'
        publishNonDefault true
    }
}

說明:

  • defaultPublishConfig 'release',默認(rèn) library 只會(huì)生產(chǎn) release 下的版本,此版本將會(huì)被所有項(xiàng)目使用,通過defaultPublishConfig可以控制默認(rèn)生產(chǎn)哪個(gè)版本的庫。
  • publishNonDefault true,默認(rèn)情況下不能生產(chǎn)所有版本的 library,通過設(shè)置publishNonDefault為true,可以同時(shí)生產(chǎn)所有版本的 library。

業(yè)務(wù)組件 module 依賴不同的基礎(chǔ)組件生產(chǎn)的 library,如下:

dependencies {
    // ...
    debugCompile project(path: ':baselibrary', configuration: "debug")
    releaseCompile project(path: ':baselibrary', configuration: "release")
}

在使用通過這樣的配置腳本解決了多個(gè) APK 包依賴同一組件生產(chǎn)的不同的 library,最終得到我們需要的開發(fā)/測(cè)試/生產(chǎn) APK 包。


合并多個(gè) module 到一個(gè)文件夾

studio 中的 module 我們?cè)谝脮r(shí)都是用,項(xiàng)目名 + :冒號(hào)來表示的

implementation project(':basecomponents')

注意這只是表示我們要引用這個(gè)名字的 module 了,而這個(gè) module 的地址這里我們不管

那么就可以理解為 module 的地址可以隨我們?nèi)我馀渲?,那么在哪里配?module 的地址呢,答案就是在 setting.gradle 文件里,我們給 ':basecomponents' 這個(gè) module 指定他的地址就行

比如我們想新建一個(gè)名字為 components 的文件夾存放我們的組件 module ,組件我們給2個(gè) ( basecomponents,aaa ),然后我們?cè)?setting.gradle 里指定每個(gè)項(xiàng)目的文件路徑

include ':app', ':basecomponents', ':aaa'

project(':basecomponents').projectDir = new File( 'components/basecomponents' )
project(':aaa').projectDir = new File( 'components/aaa' )
Snip20180905_2.png

一個(gè)好的組件化文檔是必須的

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

下面貼個(gè)圖

20160311130348_213.jpg
20160311130349_276.jpg

組件化的坑

組件化是好,但是坑也是不少,不好填,尤其是 databinding,dagger,bufferkinft,這是源于 studio 編譯的問題。

studio 中 module 雖然時(shí)在代碼上獨(dú)立于殼工程的,但是在編譯時(shí)最后還是要合并到殼工程中的,要不怎么達(dá)成一個(gè) APK 文件,要是多個(gè) APK 文件把不成了插件化了嘛,插件化坑更多啊。合并 module 到殼工程就會(huì)產(chǎn)生一個(gè)根本問題,module 的 R 文件數(shù)值改變了。module 的 R文件數(shù)據(jù)不是固定的,只有殼工程的 R 文件才是常量值,時(shí)不變的,module 的 R 文件數(shù)值在把 modul 的資源合并到殼工程后才會(huì)確定下來,那么這就對(duì)依靠編譯時(shí)注解的技術(shù)造成了難題,你指定的 R 路徑最后找不到,并且據(jù)說這里面還涉及注解的 final ,不了解,看到有人這么說,所以大家在開發(fā)組件化時(shí)對(duì)于帶注解技術(shù)的框架要多注意,有坑要多看才能爬過去

組件化文章:


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


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


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

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

gradle 各種常用使用

飛雪無情的 gradle 教程

吳小龍的gradle 的教程

其他

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,725評(píng)論 25 709
  • 不怕跌倒,所以飛翔 組件化開發(fā) 參考資源 Android組件化方案 為什么要組件化開發(fā) 解決問題 實(shí)際業(yè)務(wù)變化非常...
    筆墨Android閱讀 3,093評(píng)論 0 0
  • 這一生有你相伴,我不期待來世,來世太遙遠(yuǎn),我只要這一生有你相伴! 這一生有你相伴,是我們等候了無數(shù)次輪回的終結(jié),是...
    清風(fēng)過山崗閱讀 659評(píng)論 0 0
  • 【感恩張戰(zhàn)濤老師,治好媽媽十幾年的頸椎病~】我的媽媽,因?yàn)槌D陝诶?,頸椎、腰椎都不好,這兩年更甚,經(jīng)常性頭暈,雙手...
    d01aee4569f8閱讀 464評(píng)論 0 3
  • %~哎,今天好像可以查公務(wù)員考試的成績啦,你查了沒有??! &~我還沒有噶,你考的怎么樣?。?yīng)該可以吧,你的條件,應(yīng)...
    跳梁貴妃閱讀 476評(píng)論 0 2

友情鏈接更多精彩內(nèi)容