1. 程式人生 > >Android組件化之終極方案

Android組件化之終極方案

string 問題 我想 ont 建倉 組織 net 直接 互聯網技術

Android組件化項目地址:Android組件化項目AndroidModulePattern

    • Fragment或View如何支持組件化
    • 如何管理組件

Fragment或View如何支持組件化

距離 Android組件化方案 發布已經半年有余,雖說這個方案已經能夠解決一些項目的需求,但是依然不夠完美。很多開發者也在博客和GitHub中留言甚至發郵件問我,Fragment怎麽辦? 目前市面上APP的風格還是類似於微信界面的比較多,好幾個Fragment擺在主界面中,然後點擊NavigationBar上的圖標顯示不同的Fragment。但是很顯然Android組件化方案
並不適合這種情況。剛開始我給大家想了一個不是那麽優雅的折中方案,這個方案是將我們應用的MainActivity移動到“app殼工程”中,因為“app殼工程”的本身就肩負著管理和組裝業務組件的功能,因此這個MainActivity自然也就拿到了分散到其他業務組件中的Fragment,就像下圖這樣:

技術分享圖片

這個方案雖說也是可行的,但是顯然沒有達到我們期望的結果,我們理想的“app殼工程”是不應該跟業務有關的,他應該負責管理和組裝其他組件,並將這些業務組件包裝成一個可以發布到應用市場的APP,也就是說我們希望“app殼工程”不要和任何業務相關,不要耦合其他組件中的代碼,我想我可以隨意的替換那個空殼工程,而不會影響到我的APP打包,顯然這個偷懶的方案是做不到這一點的。因此我必須解決的問題是:一個業務組件如何在不依賴其他業務組件的情況下拿到這些業務組件中的Fragment或者其他View?

假設小A收到一個邀請函,邀請他要去參加一個互聯網技術會議,而這個會議在一個叫”XX大酒店“中舉行,但是小A之前並沒有聽過這個酒店,那麽他怎麽才能找到這個酒店並參加會議呢?大多數同學都會習慣性的打開百度地圖,然後輸入“XX大酒店”,百度地圖就會幫我找到這個酒店。但是大家有沒有想過為什麽百度地圖能找到這個酒店呢?這時候肯定有人會說:這不是廢話嗎,百度地圖都不知道還有誰知道? 這讓我想起08年那時候還沒有智能手機,我想去蘭州的一個大廈,但是我問了周圍很多路人都沒有人知道這個大廈在哪裏。而現在我們去一個地方從問路人變成了問百度地圖,那麽又回到哪句話,百度地圖是怎麽知道這些地方呢?有兩種可能:一種是有人告訴百度地圖某個地點在那裏(那些小商店就是這樣做的),另一種是百度地圖派人去城市裏晃悠把城市的所有顯著的地標都記錄下來。他們的關系就像下圖表示的這樣:

技術分享圖片

其實在 Android組件化方案 中已經有類似功能的組件:Common組件,還有另外一個就ARouter了。但是鑒於ARouter是開源庫,我們不方便去修改,那麽我們就在Common組件中做手腳。如果我想讓Common組件知道D組件中的DFragment,我們需要怎麽做呢?首先將CFragment和DFragment添加到Common組件中去,B組件想要獲取DFragment,直接就去Common組件查找就行。

技術分享圖片

這時候你一定很激動,仿佛發現了什麽絕世秘密一樣,你恨不得立馬就寫個Demo測試下這個方案。當你擼起袖子開幹後發現, What? 怎麽才能把DFragment添加到BaseApplication啊?我們都知道Application啟動後會回調onCreate()方法,貌似我們可以在Application啟動的時候在onCreate方法中把Fragment添加到BaseApplication中去。這時候你腦海肯定會付出那個黑人問號的表情,總不能讓D組件去依賴Common吧?這關系太特麽亂了。

但是經過前面的鋪墊,其實大家都發現了點什麽,那就是:只要我們能在業務組件中知道Application的生命周期,那麽我們就可以在Application onCreate 時將業務組件中的Fragment添加到Common組件中!那麽這個時候我們就需要解決:如何才能讓業務組件知道Application的生命周期呢?問題分析到這裏,我們看看下面的類圖:

技術分享圖片

首先我們Common組件中定義一個代理接口,這個代理接口定義了Application中的回調方法,然後各個業務組件實現這個代理接口,然後在onCreate方法中做自己想做的事情,而BaseApplication會在調用onCreate方法時找到所有實現了ApplicationDelegate的類,並調用這些實現類的方法,這樣業務組件就知道了我們應用程序的生命周期;當業務組件知道應用程序的聲明周期後,不僅可以在業務組件中將Fragment添加到Common組件中,而且還可以在業務組件中初始化數據,由於全局Context可以在任何組件中獲取,實際上這種方式已經等同於在Application中初始化數據。

如何管理組件

在 Android組件化方案 中,由於所有組件都在同一個項目中,並且使用 compile project(‘:組件名’) 方式依賴其他組件,這樣就會導致很多問題。

1. 編譯很慢。由於所有的組件工程都在同一個項目中,並且組件之間或app殼工程會依賴其他組件,導致每次打包APP都需要把各個組件編譯一次,如果項目中的組件達到十幾個後,結果真的很感人!隨著組件數量的增長,編譯時間幾乎呈指數性增加,這個滋味,我想每位Android開發者都深有體會。
2. 組件不方便引用。因為我們的組件是以源代碼的形式置於項目中,如果另外一個項目也需要某個組件,這個時候就只能再復制一份代碼到新項目中。這就導致一個組件存在於多個項目中,那麽最終肯定無法保證這個組件的代碼會不會被修改,也就是說組件已經無法保證唯一性了。
**3. 無法控制權限,也不方便混淆。因為項目中包含所有的組件源代碼,這時候肯定沒有辦法控制代碼權限了,假如某個組件是另外一個部門或公司提供給你用的,那麽他們當然不希望給你源代碼。

那麽如果解決這些問題呢?我想大多數Android開發者都能想到這個辦法。如果你把開源的三方庫當做一個功能組件的話,那麽很顯然,我們在使用這些三方庫的時候是通過什麽方式呢?難道你會下載它的源代碼嗎,應該很少有人會這樣做吧。那麽讓我們看看我們是怎麽引入三方庫的:

    compile ‘com.github.bumptech.glide:glide:3.8.0‘
    compile ‘io.reactivex.rxjava2:rxjava:2.1.3‘
    compile ‘io.reactivex.rxjava2:rxandroid:2.0.1‘
    compile ‘com.squareup.retrofit2:retrofit:2.3.0‘
    compile ‘com.google.code.gson:gson:2.8.1‘
    compile ‘org.greenrobot:eventbus:3.0.0‘
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

這樣大家就很熟悉了,這些開源庫一般都是上傳到maven或jcenter倉庫上供我們引用。那麽我們自己開發的組件能不能也傳到maven或jcenter倉庫呢?當然了不是讓你傳到開源倉庫上去,我的意思是我們可以在公司內部搭建一個私有的maven倉庫,將我們開發好的組件上傳到這個私有的maven倉庫上,然後內部開發人員就可以像引用三方庫那樣輕而易舉的將組件引入到項目中了,這是他們關系就像下圖這樣:

技術分享圖片

搭建倉庫管理私服主要有如下目的:

  1. 提升編譯性能和可靠性
  2. 為所有二進制軟件組件及其依賴提供配置管理中心
  3. 為你所在組織和公開倉庫提供一個高級可配置的代理
  4. 建立私有組件發布中心
  5. 通過改善組件的可用性、版本控制、安全、質量而提升其可維護性和可管理性。

而這也恰好解決了我們在組件化項目中碰到的問題。本來我想將Android組件化項目AndroidModulePattern 中的組件上傳到 jitpack ,然後給大家做個演示,但是很可惜,我試了很多次都失敗了,大家只能自己試試了。

Android組件化之終極方案