成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

Android組件化開發(fā)實踐和案例分享

zr_hebo / 3396人閱讀

摘要:主工程具有和組件進行綁定和解綁的功能。如下圖組件化需要考慮問題考慮的問題分而治之,并行開發(fā),一切皆組件。引用阿里的框架,通過注解方式進行頁面跳轉(zhuǎn)。

目錄介紹

1.為什么要組件化

1.1 為什么要組件化

1.2 現(xiàn)階段遇到的問題

2.組件化的概念

2.1 什么是組件化

2.2 區(qū)分模塊化與組件化

2.3 組件化優(yōu)勢好處

2.4 區(qū)分組件化和插件化

2.5 application和library

3.創(chuàng)建組件化框架

3.1 傳統(tǒng)APP架構(gòu)圖

3.2 組件化需要考慮問題

3.3 架構(gòu)設(shè)計圖

3.4 組件通信是通過路由轉(zhuǎn)發(fā)

3.5 解決考慮問題

3.6 業(yè)務(wù)組件的生命周期

3.7 Fragment通信難點

4.實際開發(fā)案例

4.1 組件化實踐的開源項目

4.1 如何創(chuàng)建模塊

4.2 如何建立依賴

4.3 如何統(tǒng)一配置文件

4.4 組件化的基礎(chǔ)庫

4.5 組件模式和集成模式如何切換

4.6 組件化解決重復(fù)依賴

4.7 組件化注意要點

4.8 組件化時資源名沖突

4.9 組件化開發(fā)遇到問題

5.組件間通信

5.1 選擇那個開源路由庫

5.2 阿里Arouter基礎(chǔ)原理

5.3 使用Arouter注意事項

6.關(guān)于其他

6.1 參考博客鏈接

6.2 我的博客介紹

6.3 開源項目地址

1.為什么要組件化 1.1 為什么要組件化

APP迭代維護成本增高

投資界,新芽,項目工廠等APP自身在飛速發(fā)展,版本不斷迭代,新功能不斷增加,業(yè)務(wù)模塊數(shù)量不斷增加,業(yè)務(wù)上的處理邏輯越變越復(fù)雜,同時每個模塊代碼也變得越來越多,這就引發(fā)一個問題,所維護的代碼成本越來越高,稍微一改動可能就牽一發(fā)而動全身,改個小的功能點就需要回歸整個APP測試,這就對開發(fā)和維護帶來很大的挑戰(zhàn)。

多人組合需要組件化

APP 架構(gòu)方式是單一工程模式,業(yè)務(wù)規(guī)模擴大,隨之帶來的是團隊規(guī)模擴大,那就涉及到多人協(xié)作問題,每個移動端軟件開發(fā)人員勢必要熟悉如此之多代碼,如果不按照一定的模塊組件機制去劃分,將很難進行多人協(xié)作開發(fā),隨著單一項目變大,而且Andorid項目在編譯代碼方面就會變得非常卡頓,在單一工程代碼耦合嚴重,每修改一處代碼后都需要重新編譯打包測試,導(dǎo)致非常耗時。

1.2 現(xiàn)階段遇到的問題

結(jié)合投資界,新芽客戶端分析

代碼量膨脹,不利于維護,不利于新功能的開發(fā)。項目工程構(gòu)建速度慢,在一些電腦上寫兩句代碼,重新編譯整個項目,測試的話編譯速度起碼 10-20 分鐘,有的甚至更長。

不同模塊之間代碼耦合嚴重,有時候修改一處代碼而牽動許多模塊。每個模塊之間都有引用第三方庫,但有些第三方庫版本不一致,導(dǎo)致打包APP時候代碼冗余,容易引起版本沖突。

現(xiàn)有項目基于以前其他人項目基礎(chǔ)上開發(fā),經(jīng)手的人次過多,存在著不同的代碼風格,項目中代碼規(guī)范亂,類似的功能寫法卻不一樣,導(dǎo)致不統(tǒng)一。

2.組件化的概念 2.1 什么是組件化

什么是組件化呢?

組件(Component)是對數(shù)據(jù)和方法的簡單封裝,功能單一,高內(nèi)聚,并且是業(yè)務(wù)能劃分的最小粒度。

組件化是基于組件可重用的目的上,將一個大的軟件系統(tǒng)按照分離關(guān)注點的形式,拆分成多個獨立的組件,使得整個軟件系統(tǒng)也做到電路板一樣,是單個或多個組件元件組裝起來,哪個組件壞了,整個系統(tǒng)可繼續(xù)運行,而不出現(xiàn)崩潰或不正?,F(xiàn)象,做到更少的耦合和更高的內(nèi)聚。

2.2 區(qū)分模塊化與組件化

模塊化

模塊化就是將一個程序按照其功能做拆分,分成相互獨立的模塊,以便于每個模塊只包含與其功能相關(guān)的內(nèi)容,模塊我們相對熟悉,比如登錄功能可以是一個模塊,搜索功能可以是一個模塊等等。

組件化

組件化就是更關(guān)注可復(fù)用性,更注重關(guān)注點分離,如果從集合角度來看的話,可以說往往一個模塊包含了一個或多個組件,或者說模塊是一個容器,由組件組裝而成。簡單來說,組件化相比模塊化粒度更小,兩者的本質(zhì)思想都是一致的,都是把大往小的方向拆分,都是為了復(fù)用和解耦,只不過模塊化更加側(cè)重于業(yè)務(wù)功能的劃分,偏向于復(fù)用,組件化更加側(cè)重于單一功能的內(nèi)聚,偏向于解耦。

2.3 組件化優(yōu)勢好處

簡單來說就是提高工作效率,解放生產(chǎn)力,好處如下:

1.提高編譯速度,從而提高并行開發(fā)效率。

問題:那么如何提高編譯速度的呢?組件化框架可以使模塊多帶帶編譯調(diào)試,可以有效地減少編譯的時間。

2.穩(wěn)定的公共模塊采用依賴庫方式

提供給各個業(yè)務(wù)線使用,減少重復(fù)開發(fā)和維護工作量。代碼簡潔,冗余量少,維護方便,易擴展新功能。

3.每個組件有自己獨立的版本,可以獨立編譯、測試、打包和部署。

針對開發(fā)程序員多的公司,組件化很有必要,每個人負責自己的模塊,可以較少提交代碼沖突。

為新業(yè)務(wù)隨時集成提供了基礎(chǔ),所有業(yè)務(wù)可上可下,靈活多變。

各業(yè)務(wù)線研發(fā)可以互不干擾、提升協(xié)作效率,并控制產(chǎn)品質(zhì)量。

4.避免模塊之間的交叉依賴,做到低耦合、高內(nèi)聚。

5.引用的第三方庫代碼統(tǒng)一管理,避免版本統(tǒng)一,減少引入冗余庫。

這個可以創(chuàng)建一個公共的gradle管理的文件,比如一個項目有十幾個組件,想要改下某個庫或者版本號,總不至于一個個修改吧。這個時候提取公共十分有必要

6.定制項目可按需加載,組件之間可以靈活組建,快速生成不同類型的定制產(chǎn)品。

2.4 區(qū)分組件化和插件化

組件化和插件化的區(qū)別

組件化不是插件化,插件化是在【運行時】,而組件化是在【編譯時】。換句話說,插件化是基于多APK的,而組件化本質(zhì)上還是只有一個 APK。

組件化和插件化的最大區(qū)別(應(yīng)該也是唯一區(qū)別)就是組件化在運行時不具備動態(tài)添加和修改組件的功能,但是插件化是可以的。

組件化的目標

組件化的目標之一就是降低整體工程(app)與組件的依賴關(guān)系,缺少任何一個組件都是可以存在并正常運行的。app主工程具有和組件進行綁定和解綁的功能。

2.5 application和library

在studio中,對兩種module進行區(qū)分,如下所示

一種是基礎(chǔ)庫library,比如常見第三方庫都是lib,這些代碼被其他組件直接引用。

另一種是application,也稱之為Component,這種module是一個完整的功能模塊。比如分享module就是一個Component。

為了方便,統(tǒng)一把library稱之為依賴庫,而把Component稱之為組件,下面所講的組件化也主要是針對Component這種類型。

在項目的build.gradle文件中

//控制組件模式和集成模式
if (rootProject.ext.isDouBanApplication) {
    //是Component,可以獨立運行
    apply plugin: "com.android.application"
} else {
    //是lib,被依賴
    apply plugin: "com.android.library"
}

3.創(chuàng)建組件化框架 3.1 傳統(tǒng)APP架構(gòu)圖

傳統(tǒng)APP架構(gòu)圖

如圖所示,從網(wǎng)上摘來的……

存在的問題

普遍使用的 Android APP 技術(shù)架構(gòu),往往是在一個界面中存在大量的業(yè)務(wù)邏輯,而業(yè)務(wù)邏輯中充斥著各種網(wǎng)絡(luò)請求、數(shù)據(jù)操作等行為,整個項目中也沒有模塊的概念,只有簡單的以業(yè)務(wù)邏輯劃分的文件夾,并且業(yè)務(wù)之間也是直接相互調(diào)用、高度耦合在一起的。單一工程模型下的業(yè)務(wù)關(guān)系,總的來說就是:你中有我,我中有你,相互依賴,無法分離。如下圖:

3.2 組件化需要考慮問題

考慮的問題

分而治之,并行開發(fā),一切皆組件。要實現(xiàn)組件化,無論采用什么樣的技術(shù)方式,需要考慮以下七個方面問題:

代碼解耦。

如何將一個龐大的工程分成有機的整體?這個需要一步步來了!

對已存在的項目進行模塊拆分,模塊分為兩種類型,一種是功能組件模塊,封裝一些公共的方法服務(wù)等,作為依賴庫對外提供;另一種是業(yè)務(wù)組件模塊,專門處理業(yè)務(wù)邏輯等功能,這些業(yè)務(wù)組件模塊最終負責組裝APP。

組件多帶帶運行。

因為每個組件都是高度內(nèi)聚的,是一個完整的整體,如何讓其多帶帶運行和調(diào)試?

通過 Gradle腳本配置方式,進行不同環(huán)境切換,我自己操作是添加一個boolean值的開關(guān)。比如只需要把 Apply plugin: "com.android.library" 切換成Apply plugin: "com.android.application" 就可以獨立運行呢!

需要注意:當切換到application獨立運行時,需要在AndroidManifest清單文件上進行設(shè)置,因為一個多帶帶調(diào)試需要有一個入口的Activity。

組件間通信。

由于每個組件具體實現(xiàn)細節(jié)都互相不了解,但每個組件都需要給其他調(diào)用方提供服務(wù),那么主項目與組件、組件與組件之間如何通信就變成關(guān)鍵?

這個我是直接用阿里開源的路由框架,當然你可以根據(jù)需要選擇其他大廠的開源路由庫。引用阿里的ARouter框架,通過注解方式進行頁面跳轉(zhuǎn)。

組件生命周期。

這里的生命周期指的是組件在應(yīng)用中存在的時間,組件是否可以做到按需、動態(tài)使用、因此就會涉及到組件加載、卸載等管理問題。

集成調(diào)試。

在開發(fā)階段如何做到按需編譯組件?一次調(diào)試中可能有一兩個組件參與集成,這樣編譯時間就會大大降低,提高開發(fā)效率。

代碼隔離。

組件之間的交互如果還是直接引用的話,那么組件之間根本沒有做到解耦,如何從根本上避免組件之間的直接引用?目前做法是主項目和業(yè)務(wù)組件都會依賴公共基礎(chǔ)組件庫,業(yè)務(wù)組件通過路由服務(wù)依賴庫按需進行查找,用于不同組件之間的通信。

告別結(jié)構(gòu)臃腫,讓各個業(yè)務(wù)變得相對獨立,業(yè)務(wù)組件在組件模式下可以獨立開發(fā),而在集成模式下又可以變?yōu)锳AR包集成到“APP殼工程”中,組成一個完整功能的 APP。

3.3 架構(gòu)設(shè)計圖

組件化架構(gòu)圖

業(yè)務(wù)組件之間是獨立的,互相沒有關(guān)聯(lián),這些業(yè)務(wù)組件在集成模式下是一個個 Library,被 APP 殼工程所依賴,組成一個具有完整業(yè)務(wù)功能的 APP 應(yīng)用,但是在組件開發(fā)模式下,業(yè)務(wù)組件又變成了一個個Application,它們可以獨立開發(fā)和調(diào)試,由于在組件開發(fā)模式下,業(yè)務(wù)組件們的代碼量相比于完整的項目差了很遠,因此在運行時可以顯著減少編譯時間。

3.4 組件通信是通過路由轉(zhuǎn)發(fā)

傳統(tǒng)以前工程下模塊

記得剛開始進入Android開發(fā)工作時,只有一個app主工程,后期幾乎所有的需求都寫在這個app主工程里面。只有簡單的以業(yè)務(wù)邏輯劃分的文件夾,并且業(yè)務(wù)之間也是直接相互調(diào)用、高度耦合在一起的。

導(dǎo)致后期改項目為組件化的時候十分痛苦,不同模塊之間的業(yè)務(wù)邏輯實在關(guān)聯(lián)太多,但還是沒辦法,于是目錄4步驟一步步實踐。終極目標是,告別結(jié)構(gòu)臃腫,讓各個業(yè)務(wù)變得相對獨立,業(yè)務(wù)組件在組件模式下可以獨立開發(fā)。

組件化模式下如何通信

這是組件化工程模型下的業(yè)務(wù)關(guān)系,業(yè)務(wù)之間將不再直接引用和依賴,而是通過“路由”這樣一個中轉(zhuǎn)站間接產(chǎn)生聯(lián)系。在這個開源項目中,我使用的阿里開源的路由框架。關(guān)于Arouter基礎(chǔ)使用和代碼分析,可以看我這篇博客:Arouter使用與代碼解析

3.6 業(yè)務(wù)組件的生命周期

按照理想狀態(tài)的來看待的話

各個業(yè)務(wù)組件之間沒有任何依賴關(guān)系,這時我們可以把每個獨立的業(yè)務(wù)組件看成一個可運行的app,所以業(yè)務(wù)組件的生命周期和應(yīng)與獨立的app保持一致。

3.7 Fragment通信難點

在網(wǎng)上看到很多博客說,如何拆分組件,按模塊拆分,或者按照功能拆分。但很少有提到fragment在拆分組件時的疑問,這個讓我很奇怪。

先來說一個業(yè)務(wù)需求,比如一個購物商城app,有4個模塊,做法一般是一個activity+4個fragment,這個大家都很熟悉,這四個模塊分別是:首頁,發(fā)現(xiàn),購物車,我的。然后這幾個頁面是用fragment寫的,共用一個宿主activity,那么在做組件化的時候,我想把它按照業(yè)務(wù)拆分成首頁,發(fā)現(xiàn),購物車和我的四個獨立的業(yè)務(wù)模塊。

遇到疑問:

如果是拆分成四個獨立的業(yè)務(wù)模塊,那么對應(yīng)的fragment肯定要放到對應(yīng)的組件中,那么這樣操作,當主工程與該業(yè)務(wù)組件解綁的情況下,如何拿到fragment和傳遞參數(shù)進行通信。

Fragment 中 開啟Activity帶requestCode,開啟的Activity關(guān)閉后,不會回調(diào)Fragment中的onActivityResult。只會調(diào)用Fragment 所在Activity的onActivityResult。

多fragment單activity攔截器不管用,難道只能用于攔截activity的跳轉(zhuǎn)?那如果是要實現(xiàn)登錄攔截的話,那不是只能在PathReplaceService中進行了?

網(wǎng)絡(luò)解決辦法

第一個疑問:由于我使用阿里路由,所以我看到zhi1ong大佬說:用Router跳轉(zhuǎn)到這個Activity,然后帶一個參數(shù)進去,比方說tab=2,然后自己在onCreate里面自行切換。但后來嘗試,還是想問問廣大程序員有沒有更好的辦法。

第二個疑問:還是zhi1ong大佬說,通過廣播,或者在Activity中轉(zhuǎn)發(fā)這個事件,比方說讓Fragment統(tǒng)一依賴一個接口,然后在Activity中轉(zhuǎn)發(fā)。

4.實際開發(fā)案例 4.1 組件化實踐的開源項目

關(guān)于組件化開發(fā)一點感想

關(guān)于網(wǎng)上有許多關(guān)于組件化的博客,講解了什么是組件化,為何要組件化,以及組件化的好處。大多數(shù)文章提供了組件化的思路,給我著手組件化開發(fā)提供了大量的便利。感謝前輩大神的分享!雖然有一些收獲,但是很少有文章能夠給出一個整體且有效的方案,或者一個具體的Demo。

但是畢竟看博客也是為了實踐做準備,當著手將之前的開源案例改版成組件化案例時,出現(xiàn)了大量的問題,也解決了一些問題。主要是學(xué)些了組件化開發(fā)流程。

大多數(shù)公司慢慢著手組件化開發(fā),在小公司,有的人由于之前沒有做過組件化開發(fā),嘗試組件化也是挺好的;在大公司,有的人一去只是負責某個模塊,可能剛開始組件化已經(jīng)有人弄好了,那學(xué)習(xí)實踐組件化那更快一些。業(yè)余實踐,改版之前開源項目,寫了這篇博客,耗費我不少時間,要是對你有些幫助,那我就很開心呢。由于我也是個小人物,所以寫的不好,勿噴,歡迎提出建議!

關(guān)于組件化開源項目

項目整體架構(gòu)模式采用:組件化+MVP+Rx+Retrofit+design+Dagger2+VLayout+X5

包含的模塊:wanAndroid【kotlin】+干貨集中營+知乎日報+番茄Todo+精選新聞+豆瓣音樂電影小說+小說讀書+簡易記事本+搞笑視頻+經(jīng)典游戲+其他更多等等

此項目屬于業(yè)余時間練手的項目,接口數(shù)據(jù)來源均來自網(wǎng)絡(luò),如果存在侵權(quán)情況,請第一時間告知。本項目僅做學(xué)習(xí)交流使用,API數(shù)據(jù)內(nèi)容所有權(quán)歸原作公司所有,請勿用于其他用途。

關(guān)于開源組件化的項目地址:https://github.com/yangchong2...

4.1 如何創(chuàng)建模塊

根據(jù)3.3 架構(gòu)設(shè)計圖可以知道

主工程:

除了一些全局配置和主 Activity 之外,不包含任何業(yè)務(wù)代碼。有的也叫做空殼app,主要是依賴業(yè)務(wù)組件進行運行。

業(yè)務(wù)組件:

最上層的業(yè)務(wù),每個組件表示一條完整的業(yè)務(wù)線,彼此之間互相獨立。原則上來說:各個業(yè)務(wù)組件之間不能有直接依賴!所有的業(yè)務(wù)組件均需要可以做到獨立運行的效果。對于測試的時候,需要依賴多個業(yè)務(wù)組件的功能進行集成測試的時候。可以使用app殼進行多組件依賴管理運行。

該案例中分為:干活集中營,玩Android,知乎日報,微信新聞,頭條新聞,搞笑視頻,百度音樂,我的記事本,豆瓣音樂讀書電影,游戲組件等等。

功能組件:

該案例中分為,分享組件,評論反饋組件,支付組件,畫廊組件等等。同時注意,可能會涉及多個業(yè)務(wù)組件對某個功能組件進行依賴!

基礎(chǔ)組件:

支撐上層業(yè)務(wù)組件運行的基礎(chǔ)業(yè)務(wù)服務(wù)。此部分組件為上層業(yè)務(wù)組件提供基本的功能支持。

該案例中:在基礎(chǔ)組件庫中主要有,網(wǎng)絡(luò)請求,圖片加載,通信機制,工具類,分享功能,支付功能等等。當然,我把一些公共第三方庫放到了這個基礎(chǔ)組件中!

4.2 如何建立依賴

關(guān)于工程中組件依賴結(jié)構(gòu)圖如下所示

業(yè)務(wù)模塊下完整配置代碼

//控制組件模式和集成模式
if (rootProject.ext.isGankApplication) {
    apply plugin: "com.android.application"
} else {
    apply plugin: "com.android.library"
}

android {
    compileSdkVersion rootProject.ext.android["compileSdkVersion"]
    buildToolsVersion rootProject.ext.android["buildToolsVersion"]


    defaultConfig {
        minSdkVersion rootProject.ext.android["minSdkVersion"]
        targetSdkVersion rootProject.ext.android["targetSdkVersion"]
        versionCode rootProject.ext.android["versionCode"]
        versionName rootProject.ext.android["versionName"]

        if (rootProject.ext.isGankApplication){
            //組件模式下設(shè)置applicationId
            applicationId "com.ycbjie.gank"
        }
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [AROUTER_MODULE_NAME: project.getName()]
            }
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }

    //jdk1.8
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    sourceSets {
        main {
            if (rootProject.ext.isGankApplication) {
                manifest.srcFile "src/main/module/AndroidManifest.xml"
            } else {
                manifest.srcFile "src/main/AndroidManifest.xml"
            }
            jniLibs.srcDirs = ["libs"]
        }
    }

}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation project(":library")
    annotationProcessor rootProject.ext.dependencies["router-compiler"]
}

4.3 如何統(tǒng)一配置文件

由于組件化實踐中模塊比較多,因此配置gradle,添加依賴庫時,需要考慮簡化工作。那么究竟如何做呢?

第一步,首先在項目根目錄下創(chuàng)建一個yc.gradle文件。實際開發(fā)中只需要更改該文件中版本信息即可。

我在網(wǎng)上看到的絕大多數(shù)案例,都是通過一個開關(guān)控件組件模式和集成模式的切換,但是這里我配置了多個組件的開關(guān),分別控制對應(yīng)的組件切換狀態(tài)。

ext {

    isApplication = false  //false:作為Lib組件存在, true:作為application存在
    isAndroidApplication = false  //玩Android模塊開關(guān),false:作為Lib組件存在, true:作為application存在
    isLoveApplication = false  //愛意表達模塊開關(guān),false:作為Lib組件存在, true:作為application存在
    isVideoApplication = false  //視頻模塊開關(guān),false:作為Lib組件存在, true:作為application存在
    isNoteApplication = false  //記事本模塊開關(guān),false:作為Lib組件存在, true:作為application存在
    isBookApplication = false  //book模塊開關(guān),false:作為Lib組件存在, true:作為application存在
    isDouBanApplication = false  //豆瓣模塊開關(guān),false:作為Lib組件存在, true:作為application存在
    isGankApplication = false  //干貨模塊開關(guān),false:作為Lib組件存在, true:作為application存在
    isMusicApplication = false  //音樂模塊開關(guān),false:作為Lib組件存在, true:作為application存在
    isNewsApplication = false  //新聞模塊開關(guān),false:作為Lib組件存在, true:作為application存在
    isToDoApplication = false  //todo模塊開關(guān),false:作為Lib組件存在, true:作為application存在
    isZhiHuApplication = false  //知乎模塊開關(guān),false:作為Lib組件存在, true:作為application存在
    isOtherApplication = false  //其他模塊開關(guān),false:作為Lib組件存在, true:作為application存在
    
    android = [
               compileSdkVersion       : 28,
               buildToolsVersion       : "28.0.3",
               minSdkVersion           : 17,
               targetSdkVersion        : 28,
               versionCode             : 22,
               versionName             : "1.8.2"    //必須是int或者float,否則影響線上升級
    ]

    version = [
               androidSupportSdkVersion: "28.0.0",
               retrofitSdkVersion      : "2.4.0",
               glideSdkVersion         : "4.8.0",
               canarySdkVersion        : "1.5.4",
               constraintVersion       : "1.0.2"
    ]

    dependencies = [
                //support
                "appcompat-v7"             : "com.android.support:appcompat-v7:${version["androidSupportSdkVersion"]}",
                "multidex"                 : "com.android.support:multidex:1.0.1",
                //network
                "retrofit"                 : "com.squareup.retrofit2:retrofit:${version["retrofitSdkVersion"]}",
                "retrofit-converter-gson"  : "com.squareup.retrofit2:converter-gson:${version["retrofitSdkVersion"]}",
                "retrofit-adapter-rxjava"  : "com.squareup.retrofit2:adapter-rxjava2:${version["retrofitSdkVersion"]}",
                //這里省略一部分代碼
        ]
}

第二步,然后在項目中的lib【注意這里是放到基礎(chǔ)組件庫的build.gradle】中添加代碼,如下所示

apply plugin: "com.android.library"

android {
    compileSdkVersion rootProject.ext.android["compileSdkVersion"]
    buildToolsVersion rootProject.ext.android["buildToolsVersion"]


    defaultConfig {
        minSdkVersion rootProject.ext.android["minSdkVersion"]
        targetSdkVersion rootProject.ext.android["targetSdkVersion"]
        versionCode rootProject.ext.android["versionCode"]
        versionName rootProject.ext.android["versionName"]
    }
}


dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    api rootProject.ext.dependencies["appcompat-v7"]
    api rootProject.ext.dependencies["design"]
    api rootProject.ext.dependencies["palette"]
    api rootProject.ext.dependencies["glide"]
    api (rootProject.ext.dependencies["glide-transformations"]){
        exclude module: "glide"
    }
    annotationProcessor rootProject.ext.dependencies["glide-compiler"]
    api files("libs/tbs_sdk_thirdapp_v3.2.0.jar")
    api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    
    //省略部分代碼
}

第三步,在其他model中添加依賴

implementation project(":library")即可。

4.4 組件化的基礎(chǔ)庫

基礎(chǔ)庫組件封裝

基礎(chǔ)庫組件封裝庫中主要包括開發(fā)常用的一些框架。可以直接看我的項目更加直觀!

1、網(wǎng)絡(luò)請求(采用Retrofit+RxJava框架),攔截器

2、圖片加載(策略模式,Glide與Picasso之間可以切換)

3、通信機制(RxBus),路由ARouter簡單封裝工具類(不同model之間通信)

4、mvp框架,常用的base類,比如BaseActivity,BaseFragment等等

5、通用的工具類,比如切割圓角,動畫工具類等等

6、自定義view(包括對話框,ToolBar布局,圓形圖片等view的自定義)

7、共有的shape,drawable,layout,color等資源文件

8、全局初始化異步線程池封裝庫,各個組件均可以用到

組件初始化

比如,你將該案例中的新聞組件切換成獨立運行的app,那么由于新聞跳轉(zhuǎn)詳情頁需要使用到x5的WebView,因此需要對它進行初始化。最剛開始做法是,為每一個可以切換成app的組件配置一個獨立的application,然后初始化一些該組件需要初始化的任務(wù)。但是這么做,有一點不好,不是很方便管理。后來看了知乎組件化實踐方案后,該方案提出,開發(fā)了一套多線程初始化框架,每個組件只要新建若干個啟動 Task 類,并在 Task 中聲明依賴關(guān)系。但是具體怎么用到代碼中后期有待實現(xiàn)!

如何簡化不熟悉組件化的人快速適應(yīng)組件獨立運行

設(shè)置多個組件開關(guān),需要切換那個組件就改那個。如果設(shè)置一個開關(guān),要么把所有組件切成集成模式,要么把所有組件切成組件模式,有點容易出問題。更多可以往下看!

嚴格限制公共基礎(chǔ)組件的增長

隨著開發(fā)不斷進行,要注意不要往基礎(chǔ)公共組件加入太多內(nèi)容。而是應(yīng)該減小體積!倘若是基礎(chǔ)組件過于龐大,那么運行組件也是比較緩慢的!

4.5 組件模式和集成模式如何切換

在玩Android組件下的build.gradle文件,其他組件類似。

通過一個開關(guān)來控制這個狀態(tài)的切換,module如果是一個庫,會使用com.android.library插件;如果是一個應(yīng)用,則使用com.android.application插件

//控制組件模式和集成模式
if (rootProject.ext.isAndroidApplication) {
    apply plugin: "com.android.application"
} else {
    apply plugin: "com.android.library"
}

集成模式如下所示

首先需要在yc.gradle文件中設(shè)置 isApplication=false。Sync下后,發(fā)現(xiàn)該組件是library

ext {
    isAndroidApplication = false  //false:作為Lib組件存在, true:作為application存在

組件模式如下所示

首先需要在yc.gradle文件中設(shè)置 isApplication=true。Sync下后,發(fā)現(xiàn)該組件是application,即可針對模塊進行運行

ext {
    isAndroidApplication = true  //false:作為Lib組件存在, true:作為application存在

需要注意的地方,這個很重要

首先看看網(wǎng)上絕大多數(shù)的作法,非常感謝這些大神的無私奉獻!但是我覺得多個組件用一個開關(guān)控制也可以,但是sourceSets里面切換成組件app時,可以直接不用下面這么麻煩,可以復(fù)用java和res文件。

接下來看看我的做法:

下面這個配置十分重要。也就是說當該玩Android組件從library切換到application時,由于可以作為獨立app運行,所以序意設(shè)置applicationId,并且配置清單文件,如下所示!

在 library 和 application 之間切換,manifest文件也需要提供兩套

android {
    defaultConfig {
        if (rootProject.ext.isAndroidApplication){
            //組件模式下設(shè)置applicationId
            applicationId "com.ycbjie.android"
        }
    }
    sourceSets {
        main {
            if (rootProject.ext.isAndroidApplication) {
                manifest.srcFile "src/main/module/AndroidManifest.xml"
            } else {
                manifest.srcFile "src/main/AndroidManifest.xml"
            }
            jniLibs.srcDirs = ["libs"]
        }
    }
}

具體在項目中如下所示

4.6 組件化解決重復(fù)依賴

重復(fù)依賴問題說明

重復(fù)依賴問題其實在開發(fā)中經(jīng)常會遇到,比如項目 implementation 了一個A,然后在這個庫里面又 implementation 了一個B,然后你的工程中又 implementation 了一個同樣的B,就依賴了兩次。

默認情況下,如果是 aar 依賴,gradle 會自動幫我們找出新版本的庫而拋棄舊版本的重復(fù)依賴。但是如果使用的是project依賴,gradle并不會去去重,最后打包就會出現(xiàn)代碼中有重復(fù)的類了。

解決辦法,舉個例子

api(rootProject.ext.dependencies["logger"]) { 
    exclude module: "support-v4"http://根據(jù)組件名排除 
    exclude group: "android.support.v4"http://根據(jù)包名排除 
}

4.7 組件化注意要點

業(yè)務(wù)組件之間聯(lián)動導(dǎo)致耦合嚴重

比如,實際開發(fā)中,購物車和首頁商品分別是兩個組件。但是遇到產(chǎn)品需求,比如過節(jié)做個活動,發(fā)個購物券之類的需求,由于購物車和商品詳情頁都有活動,因此會造成組件經(jīng)常會發(fā)生聯(lián)動。倘若前期準備不足,隨著時間的推移,各個業(yè)務(wù)線的代碼邊界會像組件化之前的主工程一樣逐漸劣化,耦合會越來越嚴重。

第一種解決方式:使用 sourceSets 的方式將不同的業(yè)務(wù)代碼放到不同的文件夾,但是 sourceSets 的問題在于,它并不能限制各個 sourceSet 之間互相引用,所以這種方式并不太友好!

第二種解決方式:抽取需求為工具類,通過不同組件傳值而達到調(diào)用關(guān)系,這樣只需要改工具類即可改需求。但是這種只是符合需求一樣,但是用在不同模塊的場景。

組件化開發(fā)之數(shù)據(jù)庫分離

比如,我現(xiàn)在開發(fā)的視頻模塊想要給別人用,由于緩存之類需要用到數(shù)據(jù)庫,難道還要把這個lib還得依賴一個體積較大的第三方數(shù)據(jù)庫?但是使用系統(tǒng)原生sql數(shù)據(jù)庫又不太方便,怎么辦?暫時我也沒找到辦法……

4.8 組件化時資源名沖突

資源名沖突有哪些?

比如,color,shape,drawable,圖片資源,布局資源,或者anim資源等等,都有可能造成資源名稱沖突。這是為何了,有時候大家負責不同的模塊,如果不是按照統(tǒng)一規(guī)范命名,則會偶發(fā)出現(xiàn)該問題。

尤其是如果string, color,dimens這些資源分布在了代碼的各個角落,一個個去拆,非常繁瑣。其實大可不必這么做。因為android在build時,會進行資源的merge和shrink。res/values下的各個文件(styles.xml需注意)最后都只會把用到的放到intermediate/res/merged/../valus.xml,無用的都會自動刪除。并且最后我們可以使用lint來自動刪除。所以這個地方不要耗費太多的時間。

解決辦法

這個問題也不是新問題了,第三方SDK基本都會遇到,可以通過設(shè)置 resourcePrefix 來避免。設(shè)置了這個值后,你所有的資源名必須以指定的字符串做前綴,否則會報錯。但是 resourcePrefix 這個值只能限定 xml 里面的資源,并不能限定圖片資源,所有圖片資源仍然需要你手動去修改資源名。

個人建議

將color,shape等放到基礎(chǔ)庫組件中,因為所有的業(yè)務(wù)組件都會依賴基礎(chǔ)組件庫。在styles.xml需注意,寫屬性名字的時候,一定要加上前綴限定詞。假如說不加的話,有可能會在打包成aar后給其他模塊使用的時候,會出現(xiàn)屬性名名字重復(fù)的沖突,為什么呢?因為BezelImageView這個名字根本不會出現(xiàn)在intermediate/res/merged/../valus.xml里, 所以不要以為這是屬性的限定詞!

4.9 組件化開發(fā)遇到問題

如何做到各個組件化模塊能獲取到全局上下文

情景再現(xiàn)

比如,剛開始線上項目是在app主工程里創(chuàng)建的單利,那么在lib中或者后期劃分的組件化,是無法拿到主工程的application類中的上下文。這個時候可以

解決辦法

很容易,在lib里寫一個Utils工具類,然后在主工程application中初始化Utils.init(this),這樣就可以在lib和所有業(yè)務(wù)組件[已經(jīng)依賴公共基礎(chǔ)組件庫]中拿到全局上下文呢!

butterKnife使用問題

盡管網(wǎng)上有不少博客說可以解決butterKnife在不同組件之間的引用。但是我在實際開發(fā)時,遇到組件模式和集成模式切換狀態(tài)時,導(dǎo)致出現(xiàn)編譯錯誤問題。要是那位在組件化中解決butterKnife引用問題,可以告訴我,非常感謝!

當組件化是lib時

不能使用switch(R.id.xx),需要使用if..else來代替。

不要亂發(fā)bus消息

如果項目中大量的使用eventbus,那么會看到一個類中有大量的onEventMainThread()方法,寫起來很爽,閱讀起來很痛苦。

雖然說,前期使用EventBus或者RxBus發(fā)送消息來實現(xiàn)組件間通信十分方便和簡單,但是隨著業(yè)務(wù)增大,和后期不斷更新,有的還經(jīng)過多個程序員前前后后修改,會使代碼閱讀量降低。項目中發(fā)送這個Event的地方非常多,接收這個Event的地方也很多。在后期想要改進為組件化開發(fā),而進行代碼拆分時,都不敢輕舉妄動,生怕哪些事件沒有被接收。

頁面跳轉(zhuǎn)存在問題

如果一個頁面需要登陸狀態(tài)才可以查看,那么會寫if(isLogin()){//跳轉(zhuǎn)頁面}else{//跳轉(zhuǎn)到登錄頁面},每次操作都要寫這些個相同的邏輯。

原生startActivity跳轉(zhuǎn),無法監(jiān)聽到跳轉(zhuǎn)的狀態(tài),比如跳轉(zhuǎn)錯誤,成功,異常等問題。

后時候,后臺會控制從點擊按鈕【不同場景下】跳轉(zhuǎn)到不同的頁面,假如后臺配置信息錯誤,或者少了參數(shù),那么跳轉(zhuǎn)可能不成功或者導(dǎo)致崩潰,這個也沒有一個好的處理機制。

阿里推出的開源框架Arouter,便可以解決頁面跳轉(zhuǎn)問題,可以添加攔截,或者即使后臺配置參數(shù)錯誤,當監(jiān)聽到跳轉(zhuǎn)異?;蛘咛D(zhuǎn)錯誤時的狀態(tài),可以直接默認跳轉(zhuǎn)到首頁。我在該開源案例就是這么做的!

關(guān)于跳轉(zhuǎn)參數(shù)問題

先來看一下這種代碼寫法,這種寫法本沒有問題,只是在多人開發(fā)時,如果別人想要跳轉(zhuǎn)到你開發(fā)模塊的某個頁面,那么就容易傳錯值。建議將key這個值,寫成靜態(tài)常量,放到一個專門的類中。方便自己,也方便他人。

//跳轉(zhuǎn)
intent.setClass(this,CommentActivity.class);
intent.putExtra("id",id);
intent.putExtra("allNum",allNum);
intent.putExtra("shortNum",shortNum);
intent.putExtra("longNum",longNum);
startActivity(intent);


//接收
Intent intent = getIntent();
int allNum = intent.getExtras().getInt("allNum");
int shortNum = intent.getExtras().getInt("shortNum");
int longNum = intent.getExtras().getInt("longNum");
int id = intent.getExtras().getInt("id");

5.組件間通信 5.1 選擇那個開源路由庫

比較有代表性的組件化開源框架有得到得到DDComponentForAndroid、阿里Arouter、聚美Router 等等。

得到DDComponentForAndroid:一套完整有效的android組件化方案,支持組件的組件完全隔離、多帶帶調(diào)試、集成調(diào)試、組件交互、UI跳轉(zhuǎn)、動態(tài)加載卸載等功能。

阿里Arouter:對頁面、服務(wù)提供路由功能的中間件,簡單且夠用好用,網(wǎng)上的使用介紹博客也很多,在該組件化案例中,我就是使用這個。

Router:一款單品、組件化、插件化全支持的路由框架

5.2 阿里Arouter基礎(chǔ)原理

這里只是說一下基礎(chǔ)的思路

在代碼里加入的@Route注解,會在編譯時期通過apt生成一些存儲path和activityClass映射關(guān)系的類文件,然后app進程啟動的時候會拿到這些類文件,把保存這些映射關(guān)系的數(shù)據(jù)讀到內(nèi)存里(保存在map里),然后在進行路由跳轉(zhuǎn)的時候,通過build()方法傳入要到達頁面的路由地址。

添加@Route注解然后編譯一下,就可以生成這個類,然后看一下這個類。如下所示:

/**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Group$$video implements IRouteGroup {
  @Override
  public void loadInto(Map atlas) {
    atlas.put("/video/VideoActivity", RouteMeta.build(RouteType.ACTIVITY, VideoActivity.class, "/video/videoactivity", "video", null, -1, -2147483648));
  }
}

ARouter會通過它自己存儲的路由表找到路由地址對應(yīng)的Activity.class(activity.class = map.get(path)),然后new Intent(),當調(diào)用ARouter的withString()方法它的內(nèi)部會調(diào)用intent.putExtra(String name, String value),調(diào)用navigation()方法,它的內(nèi)部會調(diào)用startActivity(intent)進行跳轉(zhuǎn),這樣便可以實現(xiàn)兩個相互沒有依賴的module順利的啟動對方的Activity了。

看_ARouter類中的 _navigation方法代碼,在345行。

private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
    final Context currentContext = null == context ? mContext : context;

    switch (postcard.getType()) {
        case ACTIVITY:
            // Build intent
            final Intent intent = new Intent(currentContext, postcard.getDestination());
            intent.putExtras(postcard.getExtras());

            // Set flags.
            int flags = postcard.getFlags();
            if (-1 != flags) {
                intent.setFlags(flags);
            } else if (!(currentContext instanceof Activity)) {    // Non activity, need less one flag.
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            }

            // Set Actions
            String action = postcard.getAction();
            if (!TextUtils.isEmpty(action)) {
                intent.setAction(action);
            }

            // Navigation in main looper.
            runInMainThread(new Runnable() {
                @Override
                public void run() {
                    startActivity(requestCode, currentContext, intent, postcard, callback);
                }
            });

            break;
        case PROVIDER:
            //這里省略代碼
        case BOARDCAST:
        case CONTENT_PROVIDER:
        case FRAGMENT:
            //這里省略代碼
        case METHOD:
        case SERVICE:
        default:
            return null;
    }
    return null;
}

5.3 使用Arouter注意事項

使用阿里路由抽取工具類,方便后期維護!

首先看一下網(wǎng)絡(luò)上有一種寫法。

//首先通過注解添加下面代碼
@Route(path = "/test/TestActivity")
public class TestActivity extends BaseActivity {

}

//跳轉(zhuǎn)
ARouter.getInstance().inject("/test/TestActivity");

優(yōu)化后的寫法

下面這種做法,是方便后期維護。

//存放所有的路由路徑常量
public class ARouterConstant {
    //跳轉(zhuǎn)到視頻頁面
    public static final String ACTIVITY_VIDEO_VIDEO = "/video/VideoActivity";
    //省略部分diamagnetic
}

//存放所有的路由跳轉(zhuǎn),工具類
public class ARouterUtils {
    /**
     * 簡單的跳轉(zhuǎn)頁面
     * @param string                string目標界面對應(yīng)的路徑
     */
    public static void navigation(String string){
        if (string==null){
            return;
        }
        ARouter.getInstance().build(string).navigation();
    }
}

//調(diào)用
@Route(path = ARouterConstant.ACTIVITY_VIDEO_VIDEO)
public class VideoActivity extends BaseActivity {

}
ARouterUtils.navigation(ARouterConstant.ACTIVITY_VIDEO_VIDEO);

06.關(guān)于其他內(nèi)容介紹 6.1 關(guān)于博客匯總鏈接

1.技術(shù)博客匯總

2.開源項目匯總

3.生活博客匯總

4.喜馬拉雅音頻匯總

5.其他匯總

6.1 參考博客鏈接

Android徹底組件化方案實踐:https://www.jianshu.com/p/1b1...

教你打造一個Android組件化開發(fā)框架:https://blog.csdn.net/cdecde1...

Android組件化框架設(shè)計與實踐:https://www.jianshu.com/p/1c5...

知乎 Android 客戶端組件化實踐:https://www.jianshu.com/p/f1a...

聚美組件化實踐之路:https://juejin.im/post/5a4b44...

Android 組件化 —— 路由設(shè)計最佳實踐:https://www.jianshu.com/p/8a3...

6.2 關(guān)于我的博客

我的個人站點:www.yczbj.org,www.ycbjie.cn

github:https://github.com/yangchong211

知乎:https://www.zhihu.com/people/...

簡書:http://www.jianshu.com/u/b7b2...

csdn:http://my.csdn.net/m0_37700275

喜馬拉雅聽書:http://www.ximalaya.com/zhubo...

開源中國:https://my.oschina.net/zbj161...

泡在網(wǎng)上的日子:http://www.jcodecraeer.com/me...

郵箱:yangchong211@163.com

阿里云博客:https://yq.aliyun.com/users/a... 239.headeruserinfo.3.dT4bcV

segmentfault頭條:https://segmentfault.com/u/xi...

6.3 開源項目地址
組件化實踐項目開源地址:https://github.com/yangchong2...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/73157.html

相關(guān)文章

發(fā)表評論

0條評論

zr_hebo

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<