什麼是 Android 組件化

前言

我希望閱讀本篇博客的童鞋都是有一定的 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, keyClass<T>, valueT.
  • 當業務模塊被加載的時候,把對應接口的實現類 putmap 集合中
  • 當業務模塊被卸載的時候,把對應接口的實現類從 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 是更加通用的一個協議,大家都對這個概念是有的,而且比較容易接受.雖然 CCAction 也可以充當 URIPath,但是畢竟基於 URI 的還支持 Query(即?後面的鍵值對) 的使用, 路由方面是肯定比不上基於 URI

回顧組件化帶來的兩個核心問題:

  • 跳轉
  • 調用任意模塊的功能

跳轉方面,基於 URI 的明顯會更好,這點是毋庸置疑的
調用任意模塊的功能個人覺得通過服務發現的方式也會更好,因爲接口調用都是顯示調用的,方便後續的維護

選擇方案的時候不僅僅要考慮框架提供的表面功能,一定要考慮維護性,我的建議很簡單,一個框架應該儘可能的向以下幾個方面靠攏

  • 對項目的入侵儘可能的小
  • 跳轉和跨模塊功能的調用儘可能的顯示調用
    • 跳轉是不可能顯示的,所以很多框架都會附帶一個 IDEA Plugin 去幫助你把 跳轉的地方和目標界面 聯繫在一起,達到一個 "顯示" 調用
    • 跨模塊功能的調用如何用的是服務發現,其實本身就是顯示調用的
  • 配置儘可能的簡單明瞭

當然還有我沒有想到的,有興趣的可以留言.以上的框架中我推薦使用

Component,它是基於 URI 設計的,並且比其他的基於 URI 設計的功能更全,更完善,也更好用.歡迎大家使用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章