Android應用架構的發展和實踐

前言

架構是咱們組織程序,各個項目組件的一種機制。好的架構兼顧了易用性,靈活性,擴展性和複用性。現代Andorid架構已經不限於單體或者單Module了,逐漸在向着多Module和插件化動態化進行發展。markdown

這裏主要圍繞項目單體應用時的架構,單Module到多Module的演變,以及插件化的將來來講。網絡

單體應用架構

單體應用架構是指咱們的項目在單Module時的架構,此時項目通常會劃分一些層級,好比UI層,網絡層,邏輯層。這些層級怎麼進行組織呢?架構

最開始,你們剛接觸Android開發,通通是MVC。MVC的問題是佈局文件做爲View層,沒法承擔任何業務邏輯;UI的邏輯和業務邏輯都寫在Activity層,在項目體量不大的時候這樣徹底沒有問題。但是當每一個頁面的業務邏輯變成以前的2倍的時候,代碼量也會增加一倍,這大大下降了項目的擴展性和維護性。這個時候可能你會經過抽取重構的方式來緩解這種局面,但是隨着業務增多,不久又會陷入這種局面。框架

慢慢的咱們發現,將Activity層的全部業務邏輯抽出去,只剩下UI相關邏輯。這樣既清晰,又能解決上面的問題,因此MVP出現了。在MVP中,Activity充當UI層,Presenter充當業務邏輯;UI層和邏輯層交互,邏輯層和數據層交互。採用接口回調,或者EventBus的方式讓UI層和邏輯層進行通訊。maven

客戶端開發主要是和UI打交道,最好的必定是MVVM。使用databind,或者LiveData能夠替代接口回調和EventBus。關於上面這些內容,我在另外一篇文章中有更詳細的說明:juejin.cn/post/684490…ide

MVVM架構下的單體應用項目,應該有這樣幾個層級:微服務

  • 數據層,專門負責數據的存取,方式不限(網絡數據,File數據或者KV存儲)
  • VM層,專門負責執行業務邏輯和數據的處理,與數據層有交互
  • UI層,負責顯示每一個界面,彈窗等,與VM層有交互

以下圖示: 工具

單Module到多Module演變

這個演變很是像後臺應用的單體架構到微服務架構的演變,適用於公司內部有多個產品須要同時迭代的場景。隨着單體應用向多Module的演變,原先的各個組件都獨立到不一樣的Module中去了。佈局

大概有兩個階段:post

  1. 單一入口Module + 公共類庫Module
  2. 多入口Module + 多公共業務Module + 公共類庫Module

第一個階段很好理解,也是一個天然而然的演變。由於項目中不少公共的模塊,好比日誌模塊,網絡模塊,數據模塊。這些模塊與邏輯無關,能夠給任何項目使用,因此單獨開一個Module或者傳到maven庫。若是要開發新的項目,那也只是將公共類庫Module移植過去便可。

因此,第一階段的項目Module結構大概是這樣:

  • App Module,負責提供項目入口,完成各個業務邏輯功能
  • Library Module,負責提供項目公共組件,好比日誌組件,網絡組件,存儲組件
  • 其餘三方庫Module

以抖音App爲例:

上面的階段能作到功能模塊的重用,可是沒有涉及到業務邏輯的重用。新項目也有登陸註冊功能,難道要從新寫一遍麼?

你可能擔憂兩個項目的登陸註冊邏輯能同樣麼,界面也不可能同樣啊。界面確定是不同的,可是登陸註冊邏輯大部分是同樣的。這就說明咱們其實能夠對一些公共業務劃分Module,對於不同的地方,徹底能夠動態化。可是公共業務不能劃入類庫Module中,由於通用性不夠;還要注意業務Module的抽離本着只抽業務,不抽UI的原則。

當業務Module和類庫Module抽離以後,不一樣的項目咱們能夠添加不一樣的入口Module,入口Module更可能是完成入口功能,和UI定製化功能,以及完成一部分差別化的實在不能共用的業務邏輯。

因此,第二階段的項目Module結構大概是這樣:

  • App1 Module,負責提供App1的入口,完成App1的全部UI邏輯和部分不能共用的業務邏輯
  • App2 Module,負責提供App2的入口,完成App1的全部UI邏輯和部分不能共用的業務邏輯
  • Login Module,負責提供登陸註冊功能
  • Video Module,負責提供視頻相關功能
  • Library Module,負責提供公共模塊功能
  • 其餘三方Module

客戶端開發中,UI的變數最大,上面的Module劃分儘可能將變化少的東西複用,將變化大的東西剝離出來。

他們之間的調用關係應該符合這樣的規則:

  • App入口Module能夠調用業務Module和Library Module;
  • 業務Module能夠調用Library Module,業務Module之間不能相互調用,也但不能調用App入口Module,目的是保持單向調用流程
  • Library Module只能被調用。

以抖音App爲例:

若是你發現業務Module須要調用App入口Module,或者其餘狀況,可能你的Module架構設計有問題。

Module間通訊

其實上面的架構不存在Module之間的通訊,也不須要。

假設這樣一個場景: 在App1中的登陸界面,調用的Login模塊的登陸邏輯,登陸完成後須要跳轉用戶信息界面。

上面的場景只需直接調用Login模塊的邏輯便可,即使發生了不一樣UI跳轉,也不須要Module通訊,由於全部的UI都寫在App1中了。

若是當初將登陸相關的UI也抽到Login模塊中,看起來封裝度更高,其實有不少不方便。在上面的場景中,須要從Login模塊的UI調用其餘模塊的UI,這樣調用流程變得複雜,並且必需要ARouter這樣的通訊工具;問題是Login的UI在各個App中不太可能同樣,若是同樣,那麼則能夠抽進去。

插件化和熱修復

不少大廠的App功能實在是太多,若是一開始就將全部功能都歸入App中,體積下不來,問題是有一些功能不少人歷來也不用。

因此從使用程度和重要性程度能夠劃分等級,對於那些次要的功能和模塊進行動態化。一開始App只提供部分重要和必須的功能,而且提供一個class運行容器。當用戶須要哪些功能是就進行下載,下載下來的無非是一些class和資源,經過定製的類加載器來加載,並作好生命週期管理和資源與Context的統一,這就是大部分插件化框架的原理。

插件化對於大部分中小公司是不須要的,能夠根據須要採納。

熱修復是指將新功能或者Fixed Bug快速更新到用戶的App中,而不用從新下載App。大體原理是先計算出含有新功能的Apk和舊Apk之間的差別,獲得一個diff包,通常很小。而後用戶直接下載diff包,App中預先內置了class動態替換的框架,將diff包加載進來就實現了動態熱修復。目前熱修復存在一些兼容性問題。

不管是插件化仍是熱修復,不建議自研,大廠有過豐富的經驗和實踐,可直接使用目前成熟的類庫。

App Bundle

通常來講,咱們開發的App,裏面包含了各類dpi的資源,兼容各類CPU架構的so庫,這大大增長了Apk的體積。可用戶事實上只須要匹配他手機的一種dpi和一種so庫就足夠,其餘的對於用戶來講都是冗餘,上面講的插件化解決了在功能方面的冗餘問題。

能不能將全部的資源,so庫等也按需下載安裝呢?谷歌在AS3.2中提供的App Bundle功能就是幹這個的。以前用戶須要下載全部的資源,下載只會下載和本身設備匹配的資源,大大提升了產品的交付速度和交付質量,但是目前只支持Google Play。

App Bundle會將咱們Apk的全部東西打爲壓縮包上傳到Google Play。而Google Play會在用戶下載的時候,根據設備特性生成優化過的Apk給用戶安裝。

App Bundle也支持動態apk,支持將暫時不須要的功能配置爲動態功能,在用戶須要的時候下載,也就是上面的插件化的功能。

App Bundle應該是插件化和動態化的將來,從工程建設的角度幫開發者完成了產品的動態交付。也許,在不久的未來國內商店也會支持這種功能。

最後

每種架構都用本身的優缺點,不能盲目採用多體的架構,也不能偷懶就永遠不升級架構;最終採用什麼樣的架構要根據本身項目體量和發展來判斷。

根據個人經驗,對於大部分公司來講,多體架構的初級階段就徹底夠用了。對於同一個團隊須要同時迭代多個項目的場景,可能須要發展到多體架構的第二階段。對於海量功能的App,可能須要插件化。

這些只是我我的的看法和經驗,但願你們踊躍討論,交流一下大家的寶貴經驗,互相提升下!

相關文章
相關標籤/搜索