天天看點

Android元件化Android元件化

Android元件化

本文由5個子產品組成:

  • 1.元件化與子產品化差別
  • 2.元件化家構圖
  • 3.各元件之間的跳轉
  • 4.各元件之間的通訊
  • 5.元件化優點
  • 6.Android Studio上面實作元件化
  • 1.元件化與子產品化差別
    元件化就是基于可重用的目的,将一個大的軟體系統按照分離關注點的形式,拆分成多個獨立的元件,已較少耦合。
               
  • 2.元件化家構圖
    Android元件化Android元件化
    說明:Library是各元件需要依賴的一些公用庫,Router(負責各元件之間的跳轉)等
  • 3.各元件之間的跳轉

    Router

    路由的使用範圍:

    1.假設用戶端與伺服器之間已經有一套路由規則,比如營運人員配置一個活動,需要從這個活動跳轉到不同的頁面去,隻需要在背景配置一下,就可以進行相對應的跳轉。

    2.随着APP業務線越來越龐大,便于梳理各個業務之間的差別,便于維護,各個業務之間的接偶是必然的。是以在這個時候路由的功能就能夠展現出來的。簡單來說,所有的頁面跳轉通過Action方式來進行跳轉,其實就是Android提供的一個路由結構。

    3.假設存在路由,所有頁面跳轉都是通過路由的方式,那麼完全可以在伺服器上面進行配置,一旦線上某個功能出現異常,可以在跳轉的時候,路由對該功能進行攔截。

    4.當然router不僅僅隻是提供跳轉頁面的功能,當制定好一套規則以後,也可以滿足個元件之間的互相依賴需求。

    網絡上面的路由架構很多,在此我就不多做介紹了。例如ActivityRouter(https://github.com/mzule/ActivityRouter.git)

  • 4.各元件之間的通訊

    先舉個例子做一個APP:

    剛開始做的時候,大家完全是Activity, View, Adapter, Fragmen等相同類型的放在同一個地方,後來人來人往,新人接手後要修複一個BUG,要找半天,才可以找到所屬的地方,于是便衍生了以業務為隔離的分包模式,如下:

    Android元件化Android元件化
    此時可以看見,項目結構是十厘清晰明顯的,需要修改某個功能的BUG時候直接友善的多,但是後來業務需求疊代,往往一個業務需要依賴于另外一個業務,于是就變成了接下來的這樣:
    Android元件化Android元件化
    這樣依賴以後,我想大家也能夠想象這種會造成的問題。光是看着都覺得頭疼。各個業務之間耦合很嚴重,修改起來簡單的工作都會因為這個變得複雜化,修改一處地方,隻需要幾分鐘,但是判斷修改該處會不會影響到其他業務可能需要花好幾個小時。

随着業務拓展,需要做出一些外放SDK 供第三方接入,而SDK中一些一些業務與原業務中功能一樣,而原業務中可能存在各種耦合,這個時候需要提取出來所花的時間不亞于重新将該功能重寫一遍了。浪費時間,浪費人力。人力不能有效發揮其功能。

那麼怎麼去解決這個問題呢,在下面有3個解決方案:
Android EventBus。需要什麼就監聽什麼,但是需要相對應的子產品做配合。
2.所有元件都對外暴露出一個接口,統一由一個代理托管。

3.Android 底層Binder通訊機制。(該機制屬于系統架構級别的,用到一個APP應用中有些殺雞用牛刀的感覺,哈哈)。

在這重點說一下第二個:

Android元件化Android元件化
首先可以看到在ModuleProviderManager中儲存了各個元件對外暴露的執行個體,其次各個元件互相并不知道其他元件的執行個體存在,隻知道某個執行個體所暴露出來的接口。當某個元件需要調用另外一個元件中的功能時候,隻需要從ModuleProviderManager中擷取該元件的執行個體,隻不過從ModuleProviderManager傳回是對象,需要轉化為相應的接口類型。
Android元件化Android元件化

首先在Core包中聲明該元件的Interface,并對外暴露出來。

然後每個元件分别實作在Core中聲明的Interface。

在這個方案中,唯一的技術難點在于怎麼樣讓各元件的Service注冊到ModuleProviderManager中去。為何這麼說呢,其一是因為各元件依賴于Core,也就是說Core并不知道各個元件的存在的,是以誰來負責把各元件的Service注冊ModuleProviderManager需要很好的考量。(在元件可以動态化注冊的時候)顯然各元件不可能自己去進行注冊,是以需要一個第三方,但無論是哪個第三方,都需要對各個元件進行依賴。

目前想得是這麼一種方案,說的部隊還望各路大神糾正:

public class ModuleProviderManager {

    public static final String  NEW_HOUSE_SERVICE = "com.baronzhang.android.newhouse.NewHouseService";
    public static final String  SECOND_HOUSE_SERVICE = "com.baronzhang.android.secondhouse.SecondHouseService";

    private ArrayList<String> mServiceName = new ArrayList<>();


    private HashMap<String, Object> mService = new HashMap<>();

    private ModuleProviderManager() {
        mServiceName.add(NEW_HOUSE_SERVICE);
        mServiceName.add(SECOND_HOUSE_SERVICE);
    }

    private static class ModuleServiceManagerHolder {
        public static ModuleProviderManager sInstance = new ModuleProviderManager();
    }

    public static ModuleProviderManager getInstance() {
        return ModuleServiceManagerHolder.sInstance;
    }

    private void registerModuleProvider(Object object) {
        try {

            String serviceName = String.valueOf(object.getClass().getField("SERVICE_NAME").get(null));
            if (mService.containsKey(serviceName)) {
                return;
            }
            mService.put(serviceName, object);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Object getModuleProviderByName(String serviceName) {
        return mService.get(serviceName);
    }

    public void initService(){
        for (String serviceName : mServiceName){
            try {
                Class clazz = Class.forName(serviceName);
                if (null == clazz) {
                    continue;
                }
                Method method  = clazz.getMethod("getInstance");
                Object obj =method.invoke(null);
                registerModuleProvider(obj);
            }catch (Exception e){
                e.printStackTrace();
                continue;
            }
        }
    }
           

每一個元件都需要在ModuleProviderManager中進行完整目錄聲明。這樣隻需要對該元件進行初始化即可周遊所有聲明的元件,并将Service進行注冊。

  • 5.元件化優點
  • 優點

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

    2.産品元件化後能夠實作完整意義上的按需求進行産品配置和銷售,使用者可以選擇使用那些元件,元件之間可以靈活的組建。

    3.配置管理,開發,測試,打包,釋出完全控制到組建層面,并帶來很多好處.比如一個元件小版本進行更新,如果對外提供的接口沒有發生任何變化,其他元件完全不需要再進行測試.

    4.編譯,由于現有情況,因為隻有修改某一處,而其他地方并未修改,在現有架構上,則需要将項目全部重新編譯一次。而元件化以後,隻需要單獨将該元件進行編譯即可。尤其當項目過于龐大的時候,整個項目全部編譯一次需要的時間很長的時候,節省下來的時間就很可觀。

  • 缺點

    1.顆粒度無法掌握。

    2.若是各業務之間除了跳轉的聯系,還有一些業務上面的耦合,業務上的如何解耦,是一個難題。

    4.若是Activity+Fragment組合方式,則其之間進行通訊起來有些困難。解決方式為寫一個通用的Fragment抽象基類,裡面填充一些方法供與外面Activity進行互動,所有Fragment都繼承該類。通過Activity往Frangmen中注冊回調接口,供Fragment通知Acitivity。但是接口總是會有局限性的。難點在于設計一套供Activity與Fragment互動的模式,其一可以友善以後的業務拓展,其二不會加強Fragment與Activity之間的耦合,其三不會造成代碼泛濫,組織架構混亂。

    5.一般而言,在項目中需要把所有的Activity都聲明在Manifest中。若是需要通過動态打包的時候,有些生成的Manifest中含有多餘的Activity聲明。設想解決方案1.隻有一個Activity,所有View都用Fragment實作,通過Fragment與Fragment之間的跳轉解決。設想解決方案2:隻有一個Activity,但是該Activity可以在Activity棧中存在多個,分别引用不用的View。設想解決方案3:通過掉本形式動态生成Manifest,裡面隻包含啟用的元件(該方法不同于前兩種,前兩種可以通過伺服器方式動态開啟,或者關閉,而這種不行,假設打包的時候元件A沒有打包進入,則生成的Manifest中就沒有A,那麼想從伺服器啟動元件A,不太可能)。

    6.一旦采用元件方式,那麼各個元件之間是沒有關聯的,各個元件之間是不知道對方是否存在的,是以跳轉的時候需要寫一個路由來進行相對應的正确跳轉。再次如何寫一個便于使用,且便于擴充的路由就顯得十分重要。

  • 6.Android Studio上面實作元件化

    在Android Studio中,每一個元件以Library形式存在同也可以以Application形式存在,并且在每個元件下面都有2個Manifest檔案,隻需要每一個元件的Gradle檔案中如此寫到

if (isBuildModule.toBoolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}

  sourceSets {
        main {
            if (isBuildModule.toBoolean()) {
                manifest.srcFile 'src/main/debug/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/release/AndroidManifest.xml'
            }
        }
    }
在全局gradle.properties檔案中對isBuildModule進行指派。


           

可能存在的問題:

1.檔案資源沖突–可以在元件Gradle檔案中對該元件資源檔案名稱進行字首限制resourcePrefix “module1_XXXX”

2.重複依賴–如果是通過 aar 依賴, gradle 會自動幫我們找出新版本,而抛棄老版本的重複依賴。如果是以 project 的方式依賴,則在打包的時候會出現重複類。對于這種情況我們可以在 build.gradle 中将 compile 改為 provided,隻在最終的項目中 compile 對應的 library ;

本文參考文章:

https://zhuanlan.zhihu.com/p/26744821(Android 子產品化探索與實踐)

https://zhuanlan.zhihu.com/p/25420181 (安居客 Android 項目架構演進)