模塊化谴垫,組件化傻傻分不清章母?附帶組件化福利

前幾篇文章中,分析了狹義上的架構(gòu)概念翩剪,如《關(guān)于移動(dòng)架構(gòu)的思考與總結(jié)》, 《關(guān)于移動(dòng)架構(gòu)乳怎,有這一篇就夠了》。從狹義上來(lái)講前弯,Android的架構(gòu)概念就在這兒蚪缀,無(wú)論怎么變秫逝,都是加加減減一些邊邊角角的東西,不足在意询枚。

從本篇開始违帆,打算從廣義上探究一下移動(dòng)架構(gòu)的思想;包括現(xiàn)在仍然比較火熱的模塊化金蜀,組件化前方, 插件化等架構(gòu)思想。話說(shuō)在前面廉油,本篇旨在說(shuō)明當(dāng)前主流架構(gòu)的設(shè)計(jì)概念惠险,讓大家了解當(dāng)前的架構(gòu)形式,以及主要用了什么設(shè)計(jì)思想抒线,什么設(shè)計(jì)思路班巩,算是引導(dǎo)篇...

模塊化,組件化嘶炭,插件化

上述概念已經(jīng)好久了抱慌,或許還是有一些同胞對(duì)這些概念不是很清楚,大體知道是什么眨猎,但是詳細(xì)也不知道是什么∫纸現(xiàn)在來(lái)解析一下。

單工程模式

移動(dòng)開發(fā)誕生睡陪,我們開發(fā)移動(dòng)項(xiàng)目寺渗,我相信大多用的是單工程單任務(wù)的開發(fā)模式,二話不說(shuō)兰迫,直接就開始寫起信殊,是不是這樣呢? new Project -> 分包 -> 寫起汁果。我相信都經(jīng)歷過(guò)涡拘,也寫的比較爽,為什么呢据德? 這種模式不涉及亂七八糟的處理方式鳄乏, 上手快,開發(fā)快棘利,足夠敏捷橱野。那么原因是什么呢?Mobile Project 剛起步赡译,項(xiàng)目都偏小仲吏,一些附加業(yè)務(wù)還沒(méi)綁到App上不铆。

模塊化

Android Studio出來(lái)了蝌焚,多出來(lái)了一個(gè)新的概念裹唆, Project, Module... 模塊;當(dāng)時(shí)以包的形式分離的公共包c(diǎn)ommon,現(xiàn)在成了AS中的Module只洒。大家都知道许帐,Module包含兩種格式: application, library毕谴。也就是說(shuō)成畦,一個(gè)Module就是一個(gè)小的項(xiàng)目,也是AS概念中的模塊涝开。因此我們開始設(shè)計(jì)common模塊循帐, common_business模塊,甚至db模塊舀武。模塊的好處是什么拄养? 相比于包來(lái)講,模塊更靈活银舱,耦合更低瘪匿,隨意插拔,想引入哪個(gè)就引入哪個(gè)寻馏。根據(jù)不同的關(guān)注點(diǎn)棋弥,將一個(gè)項(xiàng)目的可以共享的部分抽取出來(lái),形成獨(dú)立的Module诚欠,就是模塊化顽染。模塊化不只包含公共部分,當(dāng)然也可以是業(yè)務(wù)模塊轰绵。

組件化

平時(shí)看看論壇家乘,好多人都在問(wèn): 模塊化和組件化有什么區(qū)別? 到底有什么區(qū)別呢藏澳,其實(shí)很腥示狻;但并不是完全相同的概念翔悠。 通過(guò)以上模塊化的概念講述业崖,應(yīng)該對(duì)模塊化有了一個(gè)了解,那么區(qū)別是什么呢蓄愁?

組件化是建立在模塊化思想上的一次演進(jìn)双炕,一個(gè)變種。組件化本來(lái)就是模塊化的概念撮抓。但是組件化的核心是
什么妇斤? 是模塊角色的可轉(zhuǎn)換性。是的,就是可轉(zhuǎn)換性站超。

組件化的核心是角色的轉(zhuǎn)換荸恕。 在打包時(shí), 是library; 在調(diào)試時(shí)死相, 是application融求。

怎么理解組件化的概念 ?

Module的模式分兩種算撮, application和library生宛。 library就是引用庫(kù),如你抽取的common肮柜。 application就是一個(gè)apk陷舅, 是一個(gè)完整的項(xiàng)目。

在調(diào)試時(shí)审洞,我只關(guān)心我負(fù)責(zé)的模塊蔑赘,我希望我的模塊是一個(gè)單獨(dú)的app,因?yàn)檫@樣更小,業(yè)務(wù)更專一预明,相對(duì)來(lái)講修改與調(diào)試就會(huì)越省時(shí)省心缩赛,編譯就會(huì)越快。試想當(dāng)你需要改一段代碼撰糠,既要關(guān)注自己的酥馍,也要關(guān)注別人的,是一種什么體驗(yàn) 阅酪? 或者旨袒, 編譯一個(gè)項(xiàng)目10M的代碼和一個(gè)工程全部1G的代碼,哪個(gè)比較舒服一些术辐?

插件化

又有人問(wèn)了: 插件化和組件化又有什么區(qū)別呢砚尽?插件化嚴(yán)格意義來(lái)講,其實(shí)也算是模塊化的觀念辉词。將一個(gè)完整的工程必孤,按業(yè)務(wù)劃分為不同的插件,都是分治法的一種體現(xiàn)瑞躺》筇拢化整為零,相互配合幢哨。赡勘,越小的模塊越容易維護(hù)。 插件化按理也算是模塊化的一種體現(xiàn)捞镰,和組件化就不一個(gè)概念了闸与。那么毙替,到底有什么區(qū)別呢?

組件化的單位是組件(module)践樱。
插件化的單位是apk(一個(gè)完整的應(yīng)用)厂画。

組件化實(shí)現(xiàn)的是解耦與加快編譯, 隔離不需要關(guān)注的部分映胁。
插件化實(shí)現(xiàn)的也是解耦與加快編譯,同時(shí)實(shí)現(xiàn)熱插拔也就是熱更新甲雅。

組件化的靈活性在于按加載時(shí)機(jī)切換解孙,分離出獨(dú)立的業(yè)務(wù)組件,比如微信的朋友圈
插件化的靈活性在于是加載apk, 完全可以動(dòng)態(tài)下載抛人,動(dòng)態(tài)更新弛姜,比組件化更靈活。

組件化能做的只是妖枚, 朋友圈已經(jīng)有了廷臼,我想單獨(dú)調(diào)試,維護(hù)绝页,和別人不耦合荠商。但是和整個(gè)項(xiàng)目還是有關(guān)聯(lián)的。
插件化可以說(shuō)朋友圈就是一個(gè)app, 我需要整合了续誉,把它整合進(jìn)微信這個(gè)大的app里面

其實(shí)從框架名稱就可以看出: 組 和 插莱没。

組本來(lái)就是一個(gè)系統(tǒng),你把微信分為朋友圈酷鸦,聊天饰躲, 通訊錄按意義上劃為獨(dú)立模塊,但并不是真正意義上的獨(dú)立模塊臼隔。
插本來(lái)就是不同的apk嘹裂, 你把微信的朋友圈,聊天摔握,通訊錄單獨(dú)做一個(gè)完全獨(dú)立的app, 需要微信的時(shí)候插在一起寄狼,就是一個(gè)大型的app了。

插件化的加載是動(dòng)態(tài)的氨淌,這點(diǎn)很重要例嘱,也是靈活的根源。

以上是對(duì)三個(gè)思想的解析宁舰,相信應(yīng)該能明白不同的概念的具體意義和區(qū)別在哪了拼卵。在《關(guān)于移動(dòng)架構(gòu)的思考與總結(jié)》中我指出,所謂架構(gòu)蛮艰,無(wú)非兩個(gè)方面: 分層和通信方式腋腮。 其實(shí)廣義的架構(gòu)也可以說(shuō)是這兩個(gè)方面:子模塊(子系統(tǒng))劃分和通信。

子模塊劃分

除了大家公認(rèn)的common部分, 業(yè)務(wù)模塊的劃分尤為重要即寡,相比于狹義上的架構(gòu)徊哑,廣義上的子系統(tǒng)的劃分的關(guān)注點(diǎn),很考驗(yàn)技術(shù)經(jīng)驗(yàn)以及對(duì)業(yè)務(wù)的理解聪富。

通信方式

模塊化的通信方式莺丑,無(wú)非是相互引入;我抽取了common, 其他模塊使用自然要引入這個(gè)module
組件化的通信方式墩蔓,按理說(shuō)可以劃分為多種梢莽,主流的是隱式和路由。隱式的存在使解耦與靈活大大降低奸披,因此路由是主流
插件化的通信方式昏名,不同插件本身就是不同的進(jìn)程了。因此通信方式偏向于Binder機(jī)制類似的進(jìn)程間通信

廢話說(shuō)了這么多阵面,其實(shí)本篇作為組件化的引導(dǎo)篇轻局,本意是要探究一下組件化的思路的,嗯样刷,本篇只講思路仑扑;其實(shí)思路清晰了,結(jié)合一定的技術(shù)儲(chǔ)備置鼻,完全可以自己來(lái)實(shí)現(xiàn)夫壁。好了,開始切入主題...


組件化的技術(shù)準(zhǔn)備

反射與apt
gradle與groovy
路由機(jī)制

情報(bào)篇

做一件事沃疮,首先要明白我們要做什么盒让, 然后劃分步驟,哪一步怎么做司蔬,最后逐個(gè)解決邑茄。這也是分治法的一種思維方式,它當(dāng)然不只是一種算法的解決思想俊啼。只有這樣肺缕,我們才會(huì)建立信息,不會(huì)一下子被嚇傻從而放棄授帕。

組件化的思想是Module模式的切換同木。 上面已經(jīng)說(shuō)過(guò),在打包時(shí),業(yè)務(wù)module為library; 調(diào)試時(shí)跛十,業(yè)務(wù)module成了application彤路。

1.如何切換module的模式呢 ?

我相信都能想到芥映,定義一個(gè)Boolean變量作為開關(guān)酸钦。根據(jù)開關(guān)分別設(shè)置module的模式,如下

if (isModule) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}
2.兩種模式的區(qū)別是什么岸夯?
1. applicationId (包的配置)             
   只存在于apply plugin: 'com.android.application'模式下

2. Manifest.xml(主頁(yè)面的配置)
    集成模式下,使用app模塊下的Manifest.xml配置径筏; 組件模式下,使用組件自己的Manifest.xml配置

3. Application
    不同的組件肯定有自己的初始化的資源或框架,因此自定義的Application也是必要的。但是集成模式下棺滞,會(huì)造成重復(fù)的Application
3. 面臨的問(wèn)題
問(wèn)題1:多業(yè)務(wù)模塊下的統(tǒng)一配置
問(wèn)題2:Application分發(fā)
問(wèn)題3:資源的沖突
注意:不同的業(yè)務(wù)模塊禁止彼此依賴

解決方案1:

不同的模塊(20個(gè)業(yè)務(wù)模塊)的配置,必須做到統(tǒng)一配置矢渊。在Java代碼實(shí)現(xiàn)統(tǒng)一配置继准,SO Easy ~ 但是在gradle中呢 ? 那就是定義一個(gè)配置文件昆淡,統(tǒng)一存放需要配置的項(xiàng)锰瘸。如下

ext {

    isModule = false // 組件開關(guān): true 組件 false 集成

    defaultConfig = [
            minSdkVersion            : 14,
            targetSdkVersion         : 26,
            versionCode              : 1,
            versionName              : "1.0",
            testInstrumentationRunner: "android.support.test.runner.AndroidJUnitRunner"
    ]

    android = [
            compileSdkVersion: 26
    ]

    applicationId = [
            app  : "com.archer.componentsarchitecture",
            card1: "com.archer.card1",
            card2: "com.archer.card2"
    ]

    supportLibrary = "26.1.0"
    appcompatv7a = "com.android.support:appcompat-v7:${supportLibrary}"

    resourcePrefixs =[
            card1: "card1",
            card2: "card2"
    ]

    router = [
            arouter: "com.alibaba:arouter-api:1.2.1.1",
            processor: "com.alibaba:arouter-compiler:1.1.2.1"
    ]
}

在Project下創(chuàng)建一個(gè)config.gradle(什么刽严?創(chuàng)建不了昂灵?那就把Project自帶的build.gradle復(fù)制一份rename & clear)。 ext是groovy提供的擴(kuò)展參數(shù)舞萄,不可修改的眨补。 以下可以隨意定義自己的配置,如代碼倒脓。這里說(shuō)下兩個(gè)概念:

  1. 占位符 ${supportLibrary} 占據(jù)一個(gè)位置撑螺,然后用{}里面的變量補(bǔ)充,達(dá)到一致配置的目的
  2. android = [
    compileSdkVersion: 26
    ]
    以上相當(dāng)于定義了一個(gè)Map, 存放鍵值對(duì)崎弃,以Key: Value的形式甘晤,以,分隔饲做。這是groovy的寫法线婚。android 為Map的名稱,你可以用你自己的命名盆均,但是注意不要和系統(tǒng)變量沖突

以上是統(tǒng)一變量的定義塞弊,配置文件config.gradle。 配置文件定義好了泪姨,那么如何引入呢游沿?

  1. 在[Project]下的build.gradle引入配置文件


    image.png

    2.在Module中引用是通過(guò)rootProject.ext.你定義的名稱。但是每次這么用比較繁瑣肮砾,推薦定義變量實(shí)現(xiàn)诀黍,如下

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

def cfg = rootProject.ext.defaultConfig
def drd = rootProject.ext.android
def app = rootProject.ext.applicationId

android {
    compileSdkVersion drd.compileSdkVersion
    defaultConfig {
        if (isModule) {
            applicationId app['card2']
        }
        minSdkVersion cfg.minSdkVersion
        targetSdkVersion cfg.targetSdkVersion
        versionCode cfg.versionCode
        versionName cfg.versionName

        testInstrumentationRunner cfg.testInstrumentationRunner

        resourcePrefix rootProject.ext.resourcePrefixs['card2']

        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [ moduleName : project.getName() ]
            }
        }
    }

調(diào)用Groovy map中的字段的兩種方式: rootProject.ext.android.key和 rootProject.ext.android['key']


解決方案2:

application的分發(fā),錯(cuò)誤的做法是不同的組件下初始化自己的框架仗处,工具等蔗草。正確的做法是在BaseApplication或統(tǒng)一實(shí)現(xiàn)公共模塊如網(wǎng)絡(luò)咒彤, 緩存, 數(shù)據(jù)庫(kù)等的初始化咒精,在各Module實(shí)現(xiàn)自己需要的初始化镶柱,來(lái)避免重復(fù)的初始化與沖突。


解決方案3:

資源的沖突解決辦法有兩個(gè):
1) 公共資源建議由公共模塊管理
2) 模塊私有資源模叙,添加前綴限制 (只能解決xml沖突)
3)資源謹(jǐn)慎命名

資源命名只能在開發(fā)中加以注意歇拆, 通過(guò)以上共有資源和前綴極大可能的保證資源不會(huì)沖突,且不會(huì)重復(fù)浪費(fèi)范咨。至于萬(wàn)一的沖突故觅,只能交給開發(fā)規(guī)范了。


解決方案4:

這個(gè)是新加的渠啊,也就是前面說(shuō)的输吏,怎么控制application和library的轉(zhuǎn)換,全部配置如下:

// 自由控制模式轉(zhuǎn)換
if (isModule) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}

// 包名配置
 defaultConfig {
        if (isModule) {
            applicationId app['card2']
        }
}
// Manifest.xml  application配置
 sourceSets {
        main {
            if (isModule) {
                // src/main下新建文件夾替蛉,存放組件模式下的Manifest.xml與Application
                manifest.srcFile 'src/main/component/AndroidManifest.xml'
                java.srcDirs = ['src/main/java', 'src/main/component/java']
            } else {
                // library模式下不需要Application
                manifest.srcFile 'src/main/AndroidManifest.xml'
                java.srcDirs 'src/main/java'
            }
        }
    }

以上配置在相應(yīng)Module中的build.gradle的android下


本來(lái)打算出這篇為Router原理思想的贯溅,結(jié)果為了引導(dǎo)從模塊化的概念直到組件化的核心概念以及初步實(shí)現(xiàn)。因?yàn)檎娴牟簧偃丝赡軐?duì)這些概念了解不是很清楚躲查,包括以前的我它浅,比如模塊化和組件化。從整篇來(lái)看镣煮,組件化無(wú)非就是實(shí)現(xiàn)了一次轉(zhuǎn)換姐霍,解決的一些轉(zhuǎn)換過(guò)程中涉及的問(wèn)題。沒(méi)那么難典唇, 也存在一些坑镊折,只有在開發(fā)過(guò)程中隨著遇到進(jìn)一步填平。組件化的配置核心就是library和application的toggle介衔。 真正實(shí)現(xiàn)的功能核心卻是通信部分的路由實(shí)現(xiàn)部分恨胚,下一篇講一下,如何手寫Rooter通信框架夜牡。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末与纽,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子塘装,更是在濱河造成了極大的恐慌急迂,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蹦肴,死亡現(xiàn)場(chǎng)離奇詭異僚碎,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)阴幌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門勺阐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)卷中,“玉大人,你說(shuō)我怎么就攤上這事渊抽◇≡ィ” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵懒闷,是天一觀的道長(zhǎng)十减。 經(jīng)常有香客問(wèn)我,道長(zhǎng)愤估,這世上最難降的妖魔是什么帮辟? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮玩焰,結(jié)果婚禮上由驹,老公的妹妹穿的比我還像新娘。我一直安慰自己昔园,他們只是感情好蔓榄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蒿赢,像睡著了一般润樱。 火紅的嫁衣襯著肌膚如雪渣触。 梳的紋絲不亂的頭發(fā)上羡棵,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音嗅钻,去河邊找鬼皂冰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛养篓,可吹牛的內(nèi)容都是我干的秃流。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼柳弄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼舶胀!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起碧注,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤嚣伐,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后萍丐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體轩端,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年逝变,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了基茵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奋构。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖拱层,靈堂內(nèi)的尸體忽然破棺而出弥臼,到底是詐尸還是另有隱情,我是刑警寧澤根灯,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布醋火,位于F島的核電站,受9級(jí)特大地震影響箱吕,放射性物質(zhì)發(fā)生泄漏芥驳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一茬高、第九天 我趴在偏房一處隱蔽的房頂上張望兆旬。 院中可真熱鬧,春花似錦怎栽、人聲如沸丽猬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)脚祟。三九已至,卻和暖如春强饮,著一層夾襖步出監(jiān)牢的瞬間由桌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工邮丰, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留行您,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓剪廉,卻偏偏與公主長(zhǎng)得像娃循,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子斗蒋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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

  • 2018.1.15 常州溫度:1度 今日分享有點(diǎn)長(zhǎng)哦捌斧。 自從自己走上身心靈成長(zhǎng),兩年時(shí)間來(lái)泉沾,我的家庭捞蚂,工作,人際爆哑,...
    Happy歡顏閱讀 261評(píng)論 0 1
  • (一) 伴隨著“抖茨眩”的一聲,烤箱里發(fā)出面包的香味,讓正在洗刷碗筷的易千咲變得心情愉快队贱。 果然還是美食最能治愈人心色冀。...
    Yuka君閱讀 404評(píng)論 0 3
  • 2017,這是我做的最好的事情柱嫌。 家人健康锋恬,我和馬,繼續(xù)一起编丘。
    ninvxv閱讀 192評(píng)論 0 0
  • 我讀法國(guó)作家盧梭所著《懺悔錄》一書与学,即屬偶然,又是必然嘉抓。偶然是因?yàn)樵趫D書館中瀏覽時(shí)索守,無(wú)意中看到而選中的;必然是因?yàn)?..
    謹(jǐn)言策行閱讀 223評(píng)論 0 2