前言
我希望閱讀本篇博客的童鞋都是有一定的 Android
基礎的,並且近期想實施組件化方案的.希望這篇文章能幫助到你,讓你知道什麼是組件化,有哪些可選的方案
什麼是組件化
下面這幅圖相信大家平常多多少少都能看見類似的.
最下面一層是 基礎組件層
, 包括但不止以下方面
- 存儲
- 本地存儲
- 數據庫存儲
- 文件存儲
SP
存儲- …
- 網絡請求
- 實體對象
- 基礎類
- BaseActivity、BaseFragment、BasePresenter、BaseViewModel…
- 公用的資源文件
- 公用的
Theme
- 公用的
Style
- 公用的
Color
- 公用的
Dimen
- 公用的
Drawable
- …
- 公用的
中間的是 業務模塊
每一個 業務模塊
彼此之間是沒有任務的關係,彼此的代碼和資源都是隔離的,並且不能夠相互引用,每一個都是平行的關係.
總結
而組件化最關鍵的幾點核心就是:
- 代碼和資源的隔離
- 每一個業務模塊都有
單獨運行
的能力 - 殼工程可以任意的組合某幾個
業務模塊
打包出一個全新的Apk
以上的三點就是 Android
的組件化,用一句話來解釋就是:
Android 組件化就是利用多個
Module
來表示應用的多個模塊實現代碼和資源的隔離,並且每個Module
都有單獨運行和組合的能力.
實現上述的幾點並不難,難點是如何在組件化之後,我們的代碼還能像以前一樣跳轉和使用其他業務模塊的功能
所以如何當你項目打算組件化了,你就要解決組件化之後會帶來的兩個核心問題
- 如何跳轉
- 如何調用任意模塊的功能
凡是解決了上面兩個核心問題的方案都可稱之爲組件化方案.所以組件化方案到底解決了什麼問題,每一個開發人都應該心裏有一個數,而不是跟風使用組件化方案都不知道到底解決了什麼問題,也不知道爲什麼要組件化.
如何去解決項目組件化帶來的兩個核心問題
如何跳轉
因爲每一個 業務模塊
都是互相獨立沒有絲毫的關係的,所以以前的跳轉方式和功能的調用都不管用了.比如以前的跳轉
Intent intent = new Intent(this,XXX.class);
startActivity(intent);
因爲上述代碼明確指定了 XXX.class
爲目標 Activity
,而組件化了之後你要跳轉的 Activity
很可能是其他業務模塊的,你是引用不到的,這時候你是沒辦法跳轉過去的,那麼如何去解決呢?
解決方案如下:
- 隱式跳轉
- App Link
以上兩種都是系統支持的方式,你完全可以採用這種方式去解決跳轉的問題
如何調用任意模塊的功能
每一個業務模塊本質上是一個 Lib
,被殼工程包含這個模塊的功能就在 Apk
當中了.
但是每一個 業務模塊
的功能很可能需要被其他模塊使用,而每一個 業務模塊
又是代碼和資源的隔離的.所以要實現 A 業務模塊
的功能能被其他 業務模塊
調用,那麼 A 業務模塊
就需要通過一定的方式供別的 業務模塊
調用.
可以有的做法有:
- 服務發現
- 使用通用協議
- http 協議
- Android AIDL
- …
這一步的實現明顯比跳轉的難度更難.所以爲什麼會有各種各樣的組件化的方案的誕生,他們就是幫助開發者解決這個問題的.
如果你自己去解決這些問題,你的代碼會寫的很噁心,如果你能解決這些問題並且代碼還能寫的很優雅,那麼恭喜你,你也寫了一個組件化方案
服務發現的實現思路
這裏稍微說一下如何實現服務發現這種思路的功能
假設你的業務模塊被加載和卸載會有一個類似於 生命週期
的概念,大白話就是殼功能加載和卸載 A 業務模塊
, A 業務模塊
都能知道
那麼我們可以利用下面幾步實現服務發現:
- 所有需要提供給外部的功能都封裝成接口,放到一個
基礎業務模塊
- 在一個
基礎業務模塊
中放置一個Map
,key
爲Class<T>
,value
爲T
. - 當業務模塊被加載的時候,把對應接口的實現類
put
到map
集合中 - 當業務模塊被卸載的時候,把對應接口的實現類從
map
集合中remove
基礎業務模塊
是指每一個業務模塊都會依賴的一個 業務模塊
,雖然它叫業務模塊,但是它內部不寫具體的業務代碼,而是爲每一個 業務模塊
提供一些基礎公用的代碼或者資源
上面的方式就可以解決這個問題,但是這裏分享的只是解決這個問題的思路,我們還有一個前提條件要能被通知到業務模塊被加載和卸載.
服務發現依賴的業務模塊的生命週期的實現思路
當你業務模塊被加載的時候,我上面一直在說這句話,其實模塊的情況下, A 業務模塊
被殼工程依賴,當運行的時候其實 A 業務模塊
模塊並不知道自己的狀態.只是代碼被包含到 Apk
了而已.
此時雖然殼工程依賴了 A,B,C 三個 業務模塊
,但是當程序啓動的時候,他們都不知道自己被依賴使用了,所以這裏缺少一個所謂的通知,實現的方式不考慮維護性的話也有很多:
- 每一個
業務模塊
都寫一個廣播,在殼工程加載的時候能被通知到 - 每一個
業務模塊
都寫一個Activity
,在殼工程加載某一個模塊的時候,利用上面的跳轉解決方案通知 - 每一個
業務模塊
都在指定的包下創建一個特別的類,統一實現了某接口,在殼工程加載模塊的時候,能反射到該類實現一個通知 - 類似的方法應該還有很多,我也就不一一列舉了,總之就是實現了一個通知…
總結
正因爲上面的兩個原因阻擋了你組件化的進程,而上面兩個核心問題你自己去解決不僅麻煩,而且不夠通用,所以很多組件化方案應運而生.他們不管做的有多好,最根本的就是解決了上述的兩個問題.每一個組件化方案都是如此.
有哪些代表性的組件化方案
以上的都是可用的一些方案,都從根本上解決了上述兩個問題,並且每一個框架都有各自的優點和缺點.
上述的所有方案從性質上來分分爲兩類:
- 基於
URI
的 - 基於
Action
的
什麼意思呢?
基於 URI
的就是框架的路由模塊設計的核心是圍繞 URI
設計的,天然的和 URL
等完美的結合.讓一個 URI
和一個目標界面產生 1-1 的關係,給框架一個 URI
就可以路由到一個目標界面
基於 Action
的就是所有的操作都是用 Action
表示,至於你用 Action
去做什麼,完全由你自己去實現,框架幫你做的就是在任何一個地方發起的一個 Action
,都能通知到對應模塊,讓指定模塊去處理這個 Action
.
除了 CC
的其他方案都是基於 URI
設計的, CC
是基於 Action
設計的.兩者並沒有所謂的誰好誰壞,都已經解決了上述的兩個核心問題.但是站在我的角度上看, Android 組件化
採用基於 URI
設計的方案會更好一些.畢竟 URI
是更加通用的一個協議,大家都對這個概念是有的,而且比較容易接受.雖然 CC
的 Action
也可以充當 URI
的 Path
,但是畢竟基於 URI
的還支持 Query
(即?後面的鍵值對) 的使用, 路由方面是肯定比不上基於 URI
的
回顧組件化帶來的兩個核心問題:
- 跳轉
- 調用任意模塊的功能
跳轉方面,基於 URI
的明顯會更好,這點是毋庸置疑的
調用任意模塊的功能個人覺得通過服務發現的方式也會更好,因爲接口調用都是顯示調用的,方便後續的維護
選擇方案的時候不僅僅要考慮框架提供的表面功能,一定要考慮維護性,我的建議很簡單,一個框架應該儘可能的向以下幾個方面靠攏
- 對項目的入侵儘可能的小
- 跳轉和跨模塊功能的調用儘可能的顯示調用
- 跳轉是不可能顯示的,所以很多框架都會附帶一個
IDEA Plugin
去幫助你把 跳轉的地方和目標界面 聯繫在一起,達到一個"顯示" 調用
- 跨模塊功能的調用如何用的是服務發現,其實本身就是顯示調用的
- 跳轉是不可能顯示的,所以很多框架都會附帶一個
- 配置儘可能的簡單明瞭
當然還有我沒有想到的,有興趣的可以留言.以上的框架中我推薦使用
Component,它是基於 URI
設計的,並且比其他的基於 URI
設計的功能更全,更完善,也更好用.歡迎大家使用