摘要:原文地址前言起源組件化方案分析業(yè)務(wù)組件的劃分和代碼隔離路由框架基礎(chǔ)庫的優(yōu)勢簡介什么是組件化為什么要組件化分析現(xiàn)有的組件化方案如何選擇組件化方案組件化方案描述架構(gòu)圖一覽架構(gòu)圖詳解宿主層業(yè)務(wù)層業(yè)務(wù)模塊的拆分基礎(chǔ)層核心基礎(chǔ)業(yè)務(wù)公共服務(wù)基礎(chǔ)組件其他
原文地址: https://www.jianshu.com/p/f67...
0 前言
0.1 起源
0.2 組件化方案分析
0.2.1 業(yè)務(wù)組件的劃分和代碼隔離
0.2.2 路由框架
0.2.3 基礎(chǔ)庫
0.3 ArmsComponent 的優(yōu)勢
1 簡介
1.1 什么是組件化?
1.2 為什么要組件化?
1.3 分析現(xiàn)有的組件化方案
1.4 如何選擇組件化方案?
2 組件化方案描述
2.1 架構(gòu)圖一覽
2.2 架構(gòu)圖詳解
2.2.1 宿主層
2.2.2 業(yè)務(wù)層
2.2.2.1 業(yè)務(wù)模塊的拆分
2.2.3 基礎(chǔ)層
2.2.3.1 核心基礎(chǔ)業(yè)務(wù)
2.2.3.2 公共服務(wù)
2.2.3.3 基礎(chǔ) SDK
2.2.3.3.1 MVPArms
2.2.3.3.2 UI 組件
2.2.3.3.3 其他 SDK
2.3 跨組件通信
2.3.1 為什么需要跨組件化通信?
2.3.2 跨組件通信場景
2.3.3 跨組件通信方案
2.3.4 跨組件通信方案分析
2.3.5 跨組件傳遞復(fù)雜數(shù)據(jù)格式
2.4 組件的生命周期
2.4.1 問題分析
2.4.2 可行方案分析
2.4.3 最終執(zhí)行方案
3 項(xiàng)目講解
3.1 如何讓組件獨(dú)立運(yùn)行?
3.2 配置 AndroidManifest
3.3 配置 ConfigModule
3.4 RouterHub
3.5 EventBusHub
3.6 在項(xiàng)目中使用多個(gè)不同的域名
0 前言MVPArms 從兩年前開源至今, 已經(jīng)累積了近 5k star, 獲得了上千個(gè)商業(yè)項(xiàng)目的信賴和認(rèn)可
回顧兩年前, 那時(shí) MVPArms 還沒誕生, MVP、Dagger2、Rxjava、Retrofit 這些技術(shù)在國內(nèi)才剛剛開始流行, 在網(wǎng)上能搜索到的中文學(xué)習(xí)資料遠(yuǎn)沒有現(xiàn)在這么豐富, 特別是 Dagger, 在網(wǎng)上能搜索到的文章甚至有很多講的是 Square 的 Dagger1, 學(xué)習(xí)資料的匱乏加上 Dagger2 本身就是塊硬骨頭, 讓本人在學(xué)習(xí)的道路上不知道多走了多少彎路
從那時(shí)開始, 讓初學(xué)者都能夠快速搭建一個(gè) MVP + Dagger2 + Retrofit + Rxjava 項(xiàng)目的種子就已經(jīng)深埋在心中, 后面經(jīng)過不懈的努力, MVPArms 終于誕生并開源了, 開源以后只是一直堅(jiān)持將 代碼, 注釋 和 文檔 做到極致, 沒想到的是, MVPArms 能發(fā)展到如今的體量, 感謝開源!
0.1 起源這是 MVPArms 的起源, ArmsComponent 的起源同樣相似, 從去年開始, 組件化逐漸火熱起來, 本人也在去年年初開始在公司項(xiàng)目中進(jìn)行組件化, 一切還算順利
那時(shí)同樣的種子繼續(xù)埋在了心中, 我想讓剛剛接觸組件化的初學(xué)者也能快速搭建一個(gè)中小型的組件化項(xiàng)目, 經(jīng)過一年的不斷優(yōu)化, 終于決定將其開源(MVPArms 官方組件化方案 ArmsComponent)
Github : 您的 Star 是我堅(jiān)持的動(dòng)力 ?0.2 組件化方案分析
看了很多組件化方案, 所以總結(jié)了在組件化中很重要的三個(gè)大點(diǎn):
基礎(chǔ)庫(網(wǎng)絡(luò)請(qǐng)求、圖片加載等)的封裝
路由框架(頁面跳轉(zhuǎn), 服務(wù)提供)
業(yè)務(wù)組件的劃分和代碼隔離
0.2.1 業(yè)務(wù)組件的劃分和代碼隔離先說第三點(diǎn) 業(yè)務(wù)組件的劃分和代碼隔離, 現(xiàn)在大部分的文章都圍繞著這點(diǎn), 我這里發(fā)表下個(gè)人的觀點(diǎn), 第三點(diǎn)確實(shí)是很重要的一點(diǎn), 不管是大廠的方案還是小廠的方案都有借鑒之處, 但是這點(diǎn)也是最不可能討論出最終結(jié)果和統(tǒng)一解決方案的一點(diǎn)
每個(gè)公司、每個(gè)項(xiàng)目的情況都不一樣, 大廠的方案真的適合您嗎? 不一定, 大廠幾十個(gè)業(yè)務(wù)群, 幾百號(hào)開發(fā)人員, 他們的組織結(jié)構(gòu)和項(xiàng)目規(guī)模都不是普通公司能比擬的, 如果伸拉硬套他們的方案, 進(jìn)行更嚴(yán)格更細(xì)粒度的代碼隔離, 可能產(chǎn)出的價(jià)值還不及您先前付出的代價(jià), 帶來效率的降低, 所以根據(jù)項(xiàng)目的實(shí)際情況做出靈活的調(diào)整才是項(xiàng)目負(fù)責(zé)人最應(yīng)該干的事, 這點(diǎn)我在后面會(huì)有詳細(xì)的介紹
0.2.2 路由框架陸續(xù)也有很多組件化方案開源自己的 路由框架, 是個(gè)很不錯(cuò)的開始, 我覺得大家寫的都不錯(cuò), 各有各的優(yōu)勢, 本方案也決定用別人的 路由框架, 自己寫的原理也差不多, 還不一定比別人考慮的完善, 還要自己維護(hù), 為什么不選擇一個(gè)成熟穩(wěn)定的呢?
0.2.3 基礎(chǔ)庫很多組件化文章只是在講如何拆分以及封裝基礎(chǔ)庫, 但是至今沒看到有哪個(gè)組件化方案開源過完整的基礎(chǔ)庫的, 我猜測原因可能是, 組件化方案都是從商業(yè)項(xiàng)目不斷的業(yè)務(wù)迭代中逐漸完善的, 基礎(chǔ)庫也屬于公司的核心機(jī)密, 所以不可能開源
但是基礎(chǔ)庫尤其重要, 特別是兼容組件化的基礎(chǔ)庫, 這關(guān)乎到組件化方案的根基, 根基都沒有, 何談其他更高級(jí)的功能? 但是從封裝到完善一個(gè)兼容組件化的基礎(chǔ)庫是需要很長時(shí)間的, 大多數(shù)中小公司是不愿意投入這個(gè)成本的
0.3 ArmsComponent 的優(yōu)勢MVPArms 是一個(gè)開源兩年, 成熟穩(wěn)定, 涵蓋大量主流技術(shù)且兼容組件化的基礎(chǔ)庫, MVPArms 使得 ArmsComponent 成為了唯一提供完整基礎(chǔ)庫的組件化方案, 這就是 ArmsComponent 相對(duì)于其他組件化方案最大的優(yōu)勢
因?yàn)橛辛?基礎(chǔ)庫 的存在, 再加上已有的 路由框架, 組件化中的三個(gè)大點(diǎn)就已經(jīng)占有兩個(gè)(業(yè)務(wù)組件的劃分和代碼隔離 在后面會(huì)有介紹), 因此使用 ArmsComponent 啟動(dòng)一個(gè)新項(xiàng)目, 即可快速進(jìn)行組件化, 將 Demo (組件化項(xiàng)目雛形) 克隆下來后, 稍作修改, 馬上就可以投入到業(yè)務(wù)的開發(fā)之中
ArmsComponent 對(duì)于新項(xiàng)目以及已經(jīng)開始使用 MVPArms 的項(xiàng)目將會(huì)更加便捷, 有著優(yōu)于其他組件化方案的體驗(yàn), 對(duì)于那些網(wǎng)絡(luò)請(qǐng)求, 圖片加載等基礎(chǔ)功能亂七八糟散落到項(xiàng)目各處, 沒有統(tǒng)一抽離出來的舊項(xiàng)目, 建議直接使用 MVPArms, 開始組件化
如果您不想使用 MVPArms, 覺得接入成本太大, 沒關(guān)系, 借鑒下 MVPArms 和 ArmsComponent 的代碼, 嘗試改造自己的項(xiàng)目, 也是個(gè)不錯(cuò)的選擇
1 簡介好了, 進(jìn)入正題!
1.1 什么是組件化?組件化簡單概括就是把一個(gè)功能完整的 App 或模塊拆分成多個(gè)子模塊, 每個(gè)子模塊可以獨(dú)立編譯和運(yùn)行, 也可以任意組合成另一個(gè)新的 App 或模塊, 每個(gè)模塊即不相互依賴但又可以相互交互, 遇到某些特殊情況甚至可以升級(jí)或者降級(jí)
1.2 為什么要組件化?現(xiàn)在的項(xiàng)目隨著需求的增加規(guī)模變得越來越大, 規(guī)模的增大帶來了很多煩惱, 各種業(yè)務(wù)錯(cuò)中復(fù)雜的交織在一起, 每個(gè)業(yè)務(wù)模塊之間, 代碼沒有約束, 帶來了代碼邊界的模糊, 代碼沖突時(shí)有發(fā)生, 更改一個(gè)小問題可能引起一些新的問題, 牽一發(fā)而動(dòng)全身, 增加一個(gè)新需求, 瞻前顧后的熟悉了大量前輩們寫的代碼后才敢動(dòng)手, 編譯時(shí)間也不在斷增加, 開發(fā)效率極度的下降, 在這種情況下組件化的出現(xiàn)就是為了解決以上的煩惱
1.3 分析現(xiàn)有的組件化方案很多大廠的組件化方案是以 多工程 + 多 Module 的結(jié)構(gòu)(微信, 美團(tuán)等超級(jí) App 更是以 多工程 + 多 Module + 多 P 工程(以頁面為單元的代碼隔離方式) 的三級(jí)工程結(jié)構(gòu)), 使用 Git Submodule 創(chuàng)建多個(gè)子倉庫管理各個(gè)模塊的代碼, 并將各個(gè)模塊的代碼打包成 AAR 上傳至私有 Maven 倉庫使用遠(yuǎn)程版本號(hào)依賴的方式進(jìn)行模塊間代碼的隔離
1.4 如何選擇組件化方案?按照康威定律, 系統(tǒng)架構(gòu)的設(shè)計(jì)需要根據(jù)組織間的溝通結(jié)構(gòu), 因?yàn)楝F(xiàn)在大部分項(xiàng)目的規(guī)模和開發(fā)人員的數(shù)量以及結(jié)構(gòu)還不足以需要某些大廠發(fā)布的組件化方案支撐(大廠的組織結(jié)構(gòu)和項(xiàng)目規(guī)模都非常龐大, 他們的方案不一定完全適合所有公司的項(xiàng)目), 進(jìn)行更嚴(yán)格更細(xì)粒度的代碼間以及模塊間的隔離, 盲目的使用某些組件化方案, 可能會(huì)帶來開發(fā)效率降低, 開發(fā)成本遠(yuǎn)大于收益等情況, 性價(jià)比變低, 作為項(xiàng)目負(fù)責(zé)人, 應(yīng)該根據(jù)項(xiàng)目目前的規(guī)模以及開發(fā)人員的組織結(jié)構(gòu)去選擇目前最適合的組件化方案, 做到以項(xiàng)目實(shí)際情況去制定技術(shù)方案, 而不是盲目跟隨某些大廠的技術(shù)方案讓項(xiàng)目和開發(fā)人員花費(fèi)大量時(shí)間去調(diào)整和適應(yīng)
2 組件化方案描述ArmsComponent 目前采用的是 單工程 + 多 Module 的結(jié)構(gòu), 由于 Demo 較小僅僅為了展示基本規(guī)范, 所以也只是采用源碼依賴并沒有做到遠(yuǎn)程版本號(hào)依賴組件, 代碼管理也只是采用 單倉庫 + 多分支 的方式, 這樣也是對(duì)于開發(fā)初期, 項(xiàng)目規(guī)模還較小, 開發(fā)人員也較少時(shí), 開發(fā)效率較高的方案, 如果您的項(xiàng)目規(guī)模較大, 開發(fā)人員眾多, 就可以采用上面提到的 多工程 + 多 Module, 并使用私有 Maven 倉庫管理組件版本
世界上沒有一個(gè)方案可以完美到兼顧所有情況, 并且還滿足所有人, 所有項(xiàng)目的需求, 所以項(xiàng)目負(fù)責(zé)人必須按照項(xiàng)目實(shí)際情況做出靈活的調(diào)整, 才能做出最適合自家項(xiàng)目的方案
2.1 架構(gòu)圖一覽ArmsComponent 組件化架構(gòu)圖
2.2 架構(gòu)圖詳解目前架構(gòu)一共分為三層, 從低到高依次是基礎(chǔ)層, 業(yè)務(wù)層和宿主層, 由于目前項(xiàng)目較小人員較少所以三層都集中在一個(gè)工程中, 但您可以根據(jù)項(xiàng)目的規(guī)模和開發(fā)人員的數(shù)量拆分成多個(gè)工程協(xié)同開發(fā)
2.2.1 宿主層宿主層位于最上層, 主要作用是作為一個(gè) App 殼, 將需要的模塊組裝成一個(gè)完整的 App, 這一層可以管理整個(gè) App 的生命周期(比如 Application 的初始化和各種組件以及三方庫的初始化)
2.2.2 業(yè)務(wù)層業(yè)務(wù)層位于中層, 里面主要是根據(jù)業(yè)務(wù)需求和應(yīng)用場景拆分過后的業(yè)務(wù)模塊, 每個(gè)模塊之間互不依賴, 但又可以相互交互, 比如一個(gè)商城 App 由 搜索, 訂單, 購物車, 支付 等業(yè)務(wù)模塊組成
Tips: 每個(gè)業(yè)務(wù)模塊都可以擁有自己獨(dú)有的 SDK 依賴和自己獨(dú)有的 UI 資源 (如果是其他業(yè)務(wù)模塊都可以通用的 SDK 依賴 和 UI 資源 就可以將它們抽離到 基礎(chǔ) SDK(CommonSDK 2.2.3.3) 和 UI 組件(CommonRes 2.2.3.3.2) 中)2.2.2.1 業(yè)務(wù)模塊的拆分
寫業(yè)務(wù)之前先不要急著動(dòng)手敲碼, 應(yīng)該先根據(jù)初期的產(chǎn)品需求到后期的運(yùn)營規(guī)劃結(jié)合起來清晰的梳理一下業(yè)務(wù)在未來可能會(huì)發(fā)生的發(fā)展, 確定業(yè)務(wù)之間的邊界, 以及可能會(huì)發(fā)生的變化, 最后再確定下來真正需要拆分出來的業(yè)務(wù)模塊再進(jìn)行拆分
2.2.3 基礎(chǔ)層基礎(chǔ)層位于最底層, 里面又包括 核心基礎(chǔ)業(yè)務(wù)模塊、公共服務(wù)模塊、 基礎(chǔ) SDK 模塊, 核心基礎(chǔ)業(yè)務(wù)模塊 和 公共服務(wù)模塊 主要為業(yè)務(wù)層的每個(gè)模塊服務(wù), 基礎(chǔ) SDK 模塊 含有各種功能強(qiáng)大的團(tuán)隊(duì)自行封裝的 SDK 以及第三方 SDK, 為整個(gè)平臺(tái)的基礎(chǔ)設(shè)施建設(shè)提供動(dòng)力
2.2.3.1 核心基礎(chǔ)業(yè)務(wù)核心基礎(chǔ)業(yè)務(wù) 為 業(yè)務(wù)層 的每個(gè)業(yè)務(wù)模塊提供一些與業(yè)務(wù)有關(guān)的基礎(chǔ)服務(wù), 比如在項(xiàng)目中以用戶角色分為 2 個(gè)端口, 用戶可以扮演多個(gè)角色, 但是在線上只能同時(shí)操作一個(gè)端口的業(yè)務(wù), 這時(shí)每個(gè)端口都必須提供一個(gè)角色切換的功能, 以供用戶隨時(shí)在多個(gè)角色中切換,
這時(shí)在項(xiàng)目中就需要提供一個(gè)用于用戶自由切換角色的管理類作為 核心基礎(chǔ)業(yè)務(wù) 被這 2 個(gè)端口所依賴(類似 拉勾, Boss 直聘等 App 可以在招聘者和應(yīng)聘者之間切換)
核心基礎(chǔ)業(yè)務(wù) 的劃分應(yīng)該遵循是否為業(yè)務(wù)層大部分模塊都需要的基礎(chǔ)業(yè)務(wù), 以及一些需要在各個(gè)業(yè)務(wù)模塊之間交互的業(yè)務(wù), 都可以劃分為 核心基礎(chǔ)業(yè)務(wù)
2.2.3.2 公共服務(wù)公共服務(wù) 是一個(gè)名為 CommonService 的 Module, 主要的作用是用于 業(yè)務(wù)層 各個(gè)模塊之間的交互(自定義方法和類的調(diào)用), 包含自定義 Service 接口, 和可用于跨模塊傳遞的自定義類
主要流程是:
提供服務(wù)的業(yè)務(wù)模塊:
在公共服務(wù)(CommonService) 中聲明 Service 接口 (含有需要被調(diào)用的自定義方法), 然后在自己的模塊中實(shí)現(xiàn)這個(gè) Service 接口, 再通過 ARouter API 暴露實(shí)現(xiàn)類
使用服務(wù)的業(yè)務(wù)模塊:
通過 ARouter 的 API 拿到這個(gè) Service 接口(多態(tài)持有, 實(shí)際持有實(shí)現(xiàn)類), 即可調(diào)用 Service 接口中聲明的自定義方法, 這樣就可以達(dá)到模塊之間的交互
跨模塊傳遞的自定義類:
在 公共服務(wù) 中定義需要跨模塊傳遞的自定義類后 (Service 中的自定義方法和 EventBus 中的事件實(shí)體類都可能需要用到自定義類), 就可以通過 ARouter API, 在各個(gè)模塊的頁面之間跨模塊傳遞這個(gè)自定義對(duì)象 (ARouter 要求傳遞自定義對(duì)象必須實(shí)現(xiàn) SerializationService 接口)
Tips: 建議在 CommonService 中給每個(gè)需要提供服務(wù)的業(yè)務(wù)模塊都建立一個(gè)多帶帶的包, 然后在這個(gè)包下放 Service 接口 和 需要跨模塊傳遞的自定義類, 這樣更好管理
掌握公共服務(wù)層的用法最好要了解 ARouter 的 API
點(diǎn)擊查閱 ARouter 文檔2.2.3.3 基礎(chǔ) SDK
基礎(chǔ) SDK 是一個(gè)名為 CommonSDK 的 Module, 其中包含了大量功能強(qiáng)大的 SDK, 提供給整個(gè)架構(gòu)中的所有模塊
2.2.3.3.1 MVPArms
MVPArms 是整個(gè)基礎(chǔ)層中最重要的模塊, 可謂是整個(gè)組件化架構(gòu)中的心臟, 里面提供了開發(fā)一個(gè)完整項(xiàng)目所必須的一整套 API 和 SDK, 是整個(gè)項(xiàng)目的腳手架, 我用它來統(tǒng)一整個(gè)組件化方案的基礎(chǔ)設(shè)施, 使每一個(gè)模塊更加健壯, 因?yàn)橛辛?MVPArms, 使得 ArmsComponent 成為了唯一提供完整基礎(chǔ)框架的組件化方案, 所以學(xué)習(xí) ArmsComponent 之前必須先學(xué)會(huì) MVPArms
學(xué)習(xí) MVPArms 時(shí)請(qǐng)按以下排列順序依次學(xué)習(xí):
1.點(diǎn)擊學(xué)習(xí) Demo
2.點(diǎn)擊查閱 詳細(xì)文檔
3.點(diǎn)擊下載 一鍵生成代碼插件
2.2.3.3.2 UI 組件
基礎(chǔ) SDK 中的 UI 組件 是一個(gè)名為 CommonRes 的 Module, 主要放置一些業(yè)務(wù)層可以通用的與 UI 有關(guān)的資源供所有業(yè)務(wù)層模塊使用, 便于重用、管理和規(guī)范已有的資源
Tips: 值得注意的是, 業(yè)務(wù)層的某些模塊如果出現(xiàn)有資源名命名相同的情況 (如兩個(gè)圖片命名相同), 當(dāng)在宿主層集成所有模塊時(shí)就會(huì)出現(xiàn)資源沖突的問題, 這時(shí)注意在每個(gè)模塊的 build.gradle 中使用 resourcePrefix 標(biāo)簽給每個(gè)模塊下的資源名統(tǒng)一加上不同的前綴即可解決此類問題
android { defaultConfig { minSdkVersion rootProject.ext.android["minSdkVersion"] ... } resourcePrefix "public_" }
可以放置的資源類型有:
通用的 Style, Theme
通用的 Layout
通用的 Color, Dimen, String
通用的 Shape, Selector, Interpolator
通用的 圖片資源
通用的 動(dòng)畫資源
通用的 自定義 View
通用的第三方 自定義 View
2.2.3.3.3 其他 SDK
其他 SDK 主要是 基礎(chǔ) SDK 依賴的一些業(yè)務(wù)層可以通用的 第三方庫 和 第三方 SDK (比如 ARouter, 騰訊 X5 內(nèi)核), 便于重用、管理和規(guī)范已有的 SDK 依賴
2.3 跨組件通信 2.3.1 為什么需要跨組件通信?因?yàn)楦鱾€(gè)業(yè)務(wù)模塊之間是各自獨(dú)立的, 并不會(huì)存在相互依賴的關(guān)系, 所以一個(gè)業(yè)務(wù)模塊是訪問不了其他業(yè)務(wù)模塊的代碼的, 如果想從 A 業(yè)務(wù)模塊的 A 頁面跳轉(zhuǎn)到 B 業(yè)務(wù)模塊的 B 頁面, 光靠模塊自身是不能實(shí)現(xiàn)的, 所以這時(shí)必須依靠外界的其他媒介提供這個(gè)跨組件通信的服務(wù)
2.3.2 跨組件通信場景跨組件通信主要有以下兩種場景:
第一種是組件之間的頁面跳轉(zhuǎn) (Activity 到 Activity, Fragment 到 Fragment, Activity 到 Fragment, Fragment 到 Activity) 以及跳轉(zhuǎn)時(shí)的數(shù)據(jù)傳遞 (基礎(chǔ)數(shù)據(jù)類型和可序列化的自定義類類型)
第二種是組件之間的自定義類和自定義方法的調(diào)用(組件向外提供服務(wù))
2.3.3 跨組件通信方案其實(shí)以上兩種通信場景甚至其他更高階的功能在 ARouter 中都已經(jīng)被實(shí)現(xiàn), ARouter 是 Alibaba 開源的一個(gè) Android 路由中間件, 可以滿足很多組件化的需求, 也是作為本方案中比較重要的一環(huán), 需要認(rèn)真看下文檔, 了解下基本使用
關(guān)于跨組件通信框架, 本方案不做封裝, 專業(yè)的事交給專業(yè)的人做, 此類優(yōu)秀框架為數(shù)眾多, 各有特點(diǎn), 可以根據(jù)您的需求選擇您喜歡的框架, 不一定非得是 ARouter, 選擇 ARouter 也是因?yàn)?Alibaba 出品, 開源時(shí)間較長, 使用者眾多, 相對(duì)穩(wěn)定, 出現(xiàn)問題比較好溝通
2.3.4 跨組件通信方案分析第一種組件之間的頁面跳轉(zhuǎn)不需要過多描述了, 算是 ARouter 中最基礎(chǔ)的功能, API 也比較簡單, 跳轉(zhuǎn)時(shí)想傳遞不同類型的數(shù)據(jù)也提供有相應(yīng)的 API (傳遞自定義對(duì)象, 需要實(shí)現(xiàn) SerializationService, 詳情請(qǐng)查閱 ARouter 文檔);
第二種組件之間的自定義類和自定義方法的調(diào)用要稍微復(fù)雜點(diǎn), 需要 ARouter 配合架構(gòu)中的 公共服務(wù)(CommonService) 實(shí)現(xiàn), 主要流程在 公共服務(wù)(2.2.3.2) 中已有介紹, 這里我畫了個(gè)示意圖, 以便大家更好理解
跨組件通信示意圖
此種服務(wù)提供方式叫作 接口下沉, 看圖的同時(shí)請(qǐng)配合閱讀 公共服務(wù)(2.2.3.2) 中的主要流程便于理解
本方案中還提供有 EventBus 來作為服務(wù)提供的另一種方式, 大家知道 EventBus 因?yàn)槠浣怦畹奶匦? 如果被濫用的話會(huì)使項(xiàng)目調(diào)用層次結(jié)構(gòu)混亂, 不便于維護(hù)和調(diào)試, 所以本方案使用 AndroidEventBus 其獨(dú)有的 Tag, 可以在開發(fā)時(shí)更容易定位發(fā)送事件和接受事件的代碼, 如果以組件名來作為 Tag 的前綴進(jìn)行分組, 也可以更好的統(tǒng)一管理和查看每個(gè)組件的事件, 當(dāng)然也不建議大家過多使用 EventBus
Tips: 每個(gè)跨組件通信框架提供服務(wù)的方式都不同, 您也可以選擇其他框架的服務(wù)提供方式2.3.5 跨組件傳遞復(fù)雜數(shù)據(jù)格式
在一般情況下基本數(shù)據(jù)類型就可以滿足大多數(shù)跨組件傳遞數(shù)據(jù)的需求, 但是在某些情況下也會(huì)需要傳遞復(fù)雜的自定義數(shù)據(jù)類型, 傳遞自定義類型在方案中也提供有兩種方式:
第一種在 公共服務(wù)(2.2.3.2) 中已提及, 就是在 公共服務(wù) (CommonService) 中定義這個(gè)自定義類
第二種方式也比較簡單, 直接通過解析 Json 字符串就可以傳遞
2.4 組件的生命周期每個(gè)組件 (模塊) 在測試階段都可以獨(dú)立運(yùn)行, 在獨(dú)立運(yùn)行時(shí)每個(gè)組件都可以指定自己的 Application, 這時(shí)組件自己管理生命周期就輕而易舉, 比如想在 onCreate 中初始化一些代碼都可以輕松做到, 但是當(dāng)進(jìn)入集成調(diào)試階段, 組件自己的 Application 已不可用, 每個(gè)組件都只能依賴于宿主的生命周期, 這時(shí)每個(gè)組件如果需要初始化自己獨(dú)有的代碼, 該怎么辦?
2.4.1 問題分析在集成調(diào)試階段, 宿主依賴所有組件, 但是每個(gè)組件卻不能依賴宿主, 意思是每個(gè)組件根本不知道自己的宿主是誰, 當(dāng)然也就不能通過訪問代碼的方式直接調(diào)用宿主的方法, 從而在宿主的生命周期里加入自己的邏輯代碼
如果直接將每個(gè)模塊的初始化代碼直接復(fù)制進(jìn)宿主的生命周期里, 這樣未免過于暴力, 不僅代碼耦合不易擴(kuò)展, 而且代碼還極易沖突, 所以修改宿主源碼的方式也不可行
所以有沒有什么方法可以讓每個(gè)組件在集成調(diào)試階段都可以獨(dú)自管理自己的生命周期呢?
其實(shí)解決思路很簡單, 無非就是在開發(fā)時(shí)讓每個(gè)組件可以獨(dú)立管理自己的生命周期, 在運(yùn)行時(shí)又可以讓每個(gè)組件的生命周期與宿主的生命周期進(jìn)行合并 (在不修改或增加宿主代碼的情況下完成)
2.4.2 可行方案分析想在不更改宿主代碼的情況下在宿主的生命周期中動(dòng)態(tài)插入每個(gè)組件的代碼, 這倒有點(diǎn)像 AOP 的意思
現(xiàn)有的解決方案大概有三種:
在基礎(chǔ)層中提供一個(gè)用于管理組件生命周期的管理類, 每個(gè)組件都手動(dòng)將自己的生命周期實(shí)現(xiàn)類注冊(cè)進(jìn)這個(gè)管理類, 在集成調(diào)試時(shí), 宿主在自己的 Application 對(duì)應(yīng)生命周期方法中通過管理類去遍歷調(diào)用注冊(cè)的所有生命周期實(shí)現(xiàn)類即可
使用 AnnotationProcessor 解析注解在編譯期間生成源代碼自動(dòng)注冊(cè)所有組件的生命周期實(shí)現(xiàn)類, 然后宿主再在對(duì)應(yīng)的生命周期方法中去調(diào)用
使用 Javassist 在編譯時(shí)動(dòng)態(tài)修改 class 文件, 直接在宿主的對(duì)應(yīng)生命周期方法中插入每個(gè)組件的生命周期邏輯
我最后還是選擇了第一種方法, 因?yàn)楹竺鎯煞N方法雖然使用簡單, 還可以自動(dòng)化的完成所有操作, 非常炫酷, 但是這兩種方法技術(shù)實(shí)現(xiàn)復(fù)雜, 在不同的 Gradle 版本中還會(huì)出現(xiàn)兼容性問題影響整個(gè)項(xiàng)目的開發(fā)進(jìn)度, 較難維護(hù), 還會(huì)增加編譯時(shí)間
選擇第一種方法雖然增加了幾步操作, 但是簡單明了, 便與理解和維護(hù), 后續(xù)人員加入也可以很快上手, 不受 Gradle 版本的影響, 也不會(huì)增加編譯時(shí)間
2.4.3 最終執(zhí)行方案第一種方案具體原理也沒什么好說的, 比較簡單, 大概就是在基礎(chǔ)層中定義有生命周期方法 (attachBaseContext(), onCreate() ...) 的接口, 每個(gè)組件實(shí)現(xiàn)這個(gè)接口, 然后將實(shí)現(xiàn)類注冊(cè)進(jìn)基礎(chǔ)層的管理器, 宿主通過管理器在對(duì)應(yīng)的生命周期方法中調(diào)用所有的接口實(shí)現(xiàn)類, 典型的觀察者模式, 類似注冊(cè)點(diǎn)擊事件
在 MVPArms 中這種方案的實(shí)現(xiàn)類叫作 ConfigModule, 每個(gè)組件都可以聲明一個(gè)或多個(gè) ConfigModule 實(shí)現(xiàn)類, 內(nèi)部實(shí)現(xiàn)較為復(fù)雜, 實(shí)現(xiàn)原理是 反射 + 代理 + 觀察者, 這個(gè)類也是整個(gè) MVPArms 框架提供給開發(fā)者最重要的類
它可以給 MVPArms 框架配置大量的自定義參數(shù), 包括項(xiàng)目中所有生命周期的管理 (Application, Activity, Fragment), 項(xiàng)目中所有網(wǎng)絡(luò)請(qǐng)求的管理 (Retrofit, Okhttp, Glide),為框架提供了極大的擴(kuò)展性, 使框架更加靈活
3 項(xiàng)目講解項(xiàng)目地址 : ArmsComponent3.1 如何讓組件獨(dú)立運(yùn)行?
在項(xiàng)目根目錄的 gradle.properties 中, 改變 isBuildModule 的值即可
#isBuildModule 為 true 時(shí)可以使每個(gè)組件獨(dú)立運(yùn)行, false 則可以將所有組件集成到宿主 App 中 isBuildModule=true3.2 配置 AndroidManifest
由于組件在獨(dú)立運(yùn)行時(shí)和集成到宿主時(shí)可能需要 AndroidManifest 配置不一樣的參數(shù), 比如組件在獨(dú)立運(yùn)行時(shí)需要其中的一個(gè) Activity 配置了
在組件的 build.gradle 中加入以下代碼, 即可指定不同的 AndroidManifest, 具體請(qǐng)看項(xiàng)目代碼
android { sourceSets { main { jniLibs.srcDirs = ["libs"] if (isBuildModule.toBoolean()) { manifest.srcFile "src/main/debug/AndroidManifest.xml" } else { manifest.srcFile "src/main/release/AndroidManifest.xml" } } } }3.3 配置 ConfigModule(GlobalConfiguration)
ConfigModule 在 最終執(zhí)行方案(2.4.3) 中提到過, GlobalConfiguration 是實(shí)現(xiàn)類, 他可以給框架配置大量的自定義參數(shù)
項(xiàng)目 CommonSDK 中提供有一個(gè) GlobalConfiguration 用于配置每個(gè)組件都會(huì)用到的公用配置信息, 但是每個(gè)組件可能都需要有一些私有配置, 比如初始化一些特有屬性, 所以在每個(gè)組件中也需要實(shí)現(xiàn) ConfigModule, 具體請(qǐng)看項(xiàng)目代碼
需要注意的是, 在 配置 AndroidManifest(3.2) 中提到過組件在獨(dú)立運(yùn)行時(shí)和集成到宿主時(shí)所需要的配置是不一樣的, 當(dāng)組件在獨(dú)立運(yùn)行時(shí)需要在 AndroidManifest 中聲明自己私有的 GlobalConfiguration 和 CommonSDK 公有的 GlobalConfiguration, 但在集成到宿主時(shí), 由于宿主已經(jīng)聲明了 CommonSDK 的公有 GlobalConfiguration, 所以在 AndroidManifest 只需要聲明自己私有的 GlobalConfiguration, 這里也說明了 AndroidManifest 在不同的情況需要做出不同的配置
3.4 RouterHubRouterHub 用來定義路由器的路由地址, 以組件名作為前綴, 對(duì)每個(gè)組件的路由地址進(jìn)行分組, 可以統(tǒng)一查看和管理所有分組的路由地址
路由地址的命名規(guī)則為 組件名 + 頁面名, 如訂單組件的訂單詳情頁的路由地址可以命名為 "/order/OrderDetailActivity"
ARouter 將路由地址中第一個(gè) "/" 后面的字符叫作 Group, 比如上面的示例路由地址中 order 就是 Group, 以 order 開頭的地址都被分配該 Group 下
Tips: 切記不同的組件中不能出現(xiàn)名稱一樣的 Group, 否則會(huì)發(fā)生該 Group 下的部分路由地址找不到的情況!!!
所以每個(gè)組件使用自己的組件名作為 Group 是比較好的選擇, 畢竟組件不會(huì)重名
3.5 EventBusHubAndroidEventBus 作為本方案提供的另一種跨組件通信方式 (第一種跨組件通信方式是 公共服務(wù)(2.2.3.2)), AndroidEventBus 比 greenrobot 的 EventBus 多了一個(gè) Tag, 在組件化中更容定位和管理事件
EventBusHub 用來定義 AndroidEventBus 的 Tag 字符串, 以組件名作為 Tag 前綴, 對(duì)每個(gè)組件的事件進(jìn)行分組
Tag 的命名規(guī)則為 組件名 + 頁面名 + 動(dòng)作,
比如需要使用 AndroidEventBus 通知訂單組件的訂單詳情頁進(jìn)行刷新, 可以將這個(gè)刷新方法的 Tag 命名為 "order/OrderDetailActivity/refresh"
在項(xiàng)目中, 有 知乎 、干貨集中營、稀土掘金 三個(gè)模塊, 這三個(gè)模塊網(wǎng)絡(luò)接口的域名都不一樣, 但是在項(xiàng)目中卻可以統(tǒng)一使用框架提供的同一個(gè) Retrofit 進(jìn)行網(wǎng)絡(luò)請(qǐng)求, 這是怎么做到的呢? 這是采用本人的另一個(gè)庫 RetrofitUrlManager, 它可以使 Retrofit 同時(shí)支持多個(gè) BaseUrl 以及動(dòng)態(tài)改變 BaseUrl
Hello 我叫Jessyan,如果您喜歡我的文章,可以在以下平臺(tái)關(guān)注我
GitHub: https://github.com/JessYanCoding
掘金: https://gold.xitu.io/user/57a...
簡書: http://www.jianshu.com/u/1d0c...
微博: http://weibo.com/u/1786262517
-- The end
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/11857.html
摘要:前言我在上篇文章中介紹了的官方快速組件化方案當(dāng)時(shí)一直強(qiáng)調(diào)是快速的組件化方案但是在文章中只提供了一個(gè)近萬字的官方文檔卻沒展現(xiàn)出這個(gè)組件化方案的快速之處看到近萬字的文檔后新手已經(jīng)開始瑟瑟發(fā)抖了覺得入門成本太高想放棄寫這篇文章的意義就是為了展現(xiàn)快 showImg(https://segmentfault.com/img/remote/1460000015444818); 前言 我在 上篇文章...
摘要:前言官方架構(gòu)組件在今年月份大會(huì)上被公布直到月份一直都是測試版由于工作比較繁忙期間我只是看過類似的文章但沒有在實(shí)際項(xiàng)目中使用過更沒有看過源碼所以對(duì)這幾個(gè)組件的使用很是生疏同時(shí)也覺得這幾個(gè)組件非常高大上非常神秘直到月份官方架構(gòu)組件正式版發(fā)布并且 前言 Android 官方架構(gòu)組件在今年 5 月份 Google I/O 大會(huì)上被公布, 直到 11 月份一直都是測試版, 由于工作比較繁忙, 期...
摘要:數(shù)據(jù)可視化庫超過的的可能是最流行和最廣泛的數(shù)據(jù)可視化庫。是一組組件,用于高效地渲染大型列表和表格數(shù)據(jù)。一種優(yōu)雅而靈活的方式,可以利用組件來支持實(shí)際的數(shù)據(jù)可視化。 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! React Native 組件庫 1. NativeBase showImg(https://segmentfault.com/img/bVbrLHH?w=...
閱讀 2107·2023-04-26 00:09
閱讀 3133·2021-09-26 10:12
閱讀 3501·2019-08-30 15:44
閱讀 2872·2019-08-30 13:47
閱讀 932·2019-08-23 17:56
閱讀 3236·2019-08-23 15:31
閱讀 480·2019-08-23 13:47
閱讀 2523·2019-08-23 11:56