天天看點

淺談 Android元件化概述子產品化群組件化元件化Demo總結

概述

軟體開發程序也是架構的演進過程,就拿Android來說,從最開始的MVC ,MVP ,MVVP ,再到後來的元件化,插件化,但歸根到底一切的一切,都是為了項目更好的維護、疊代,降低開發成本。

在一個項目的開發過程中,前期我們可能把所有的功能子產品都放到了一個moudle中,這樣能夠快速的開發,但随着項目壯大,開發人員和功能的增加,就回導緻代碼越來越臃腫,各個子產品之間的耦合越來越重,牽一發而動全身,這個時候為了保證項目品質,我們就需要對項目進行重構。

我們可以根據業務子產品進行查分,把不同的業務子產品放到不同的moudle中,實作各個業務之間的結構,他們又共同依賴底層公共庫,這就是子產品化的概念,但是當多個子產品中涉及到相同功能時代碼的耦合又會增加,例如有兩個子產品都需要視訊播放的功能,把視訊播放放到兩個元件中就會出現代碼重複的問題,放到公共庫感覺也不是很好,這時候就用元件化來解決這個問題

子產品化群組件化

子產品化

具體的業務子產品,例如商品詳情子產品,商品釋出子產品 ,搜尋子產品

元件化

單一的功能元件,如視訊播放元件、分享元件等,每個元件都可以以一個單獨的 module 開發,并且可以單獨抽出來作為 SDK 對外釋出使用

子產品化群組件化的思想是一樣的,都是對代碼進行拆分,但子產品化是按功能子產品進行查分(業務導向),元件化是按功能子產品進行查分(功能導向),子產品化的顆粒度更大一些,元件的顆粒度更小一些,一個項目中子產品群組件同時存在也是很常見的,各自負責各自的事情

淺談 Android元件化概述子產品化群組件化元件化Demo總結

如上圖所示 是個元件化項目的基本架構

  • 基礎庫、公共庫:項目所需要的基礎操作類,工具類 ,第三方庫的引入封裝 ,app宿主功能,各個子產品,各個元件都依賴這個庫
  • 元件層:項目用的功能子產品或者業務子產品,如:登入子產品,視訊播放元件,分享元件等
  • 應用層:宿主工程,APP的主項目,APP入口和主架子

元件化Demo

位址如下: github.com/syg13579/as… 我根據demo項目從以下幾個方面來講解

  • 1:項目分析
  • 2:元件application和library動态切換
  • 3:元件間的資料傳遞和方法調用
  • 4:元件類(例如:Fragment)的擷取,以及誇元件頁面跳轉和通訊

1:項目分析

淺談 Android元件化概述子產品化群組件化元件化Demo總結

如上圖所示,項目的主要結構

  • 應用層:app 項目的主入口
  • 元件層:goods login 商品詳情頁和登入元件
  • 基礎庫層:assemblebase用來各個元件資料和方法互動的 ,base是常用的工具類,各種類庫的封裝

2:元件application和library動态切換

在開發過程中,為了能夠實作快速開發,元件能夠獨立運作就顯的特别重要,moudle一般分為兩種

  • App 插件,id: com.android.application
  • Library 插件,id: com.android.library

我們可以通過配置可動态進行application和library的切換,我們在各個元件的gradle.properties檔案中配置一個控制切換的變量

淺談 Android元件化概述子產品化群組件化元件化Demo總結

然後在build.gradle中就可以通過isRunAlone變量來進行application和library的切換了,主要設計的點有三部分

  • plugin屬性的配置
  • applicationId的配置
  • AndroidManifest的配置
if (isRunAlone.toBoolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}

android {
    compileSdkVersion 26

    defaultConfig {
        if (isRunAlone.toBoolean()) {
            applicationId "ppzh.jd.com.goods"
        }
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    sourceSets {
        main {
            if (isRunAlone.toBoolean()) {
                manifest.srcFile 'src/main/manifest/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/AndroidManifest.xml'
            }
        }
    }

}
           

如果以上配置就可以實作application和library的切換了

3:元件間的資料傳遞和方法調用

由于主項目、元件之間,元件群組件之間不能直接通過引用進行資料傳遞和方法調用,那麼在開發的過程中怎麼進行資料傳遞和方法調用呢,可以通過「接口」+「實作」的方式進行,

assemblebase基礎庫就是用來進行資料傳遞和方法調用的,它被所有元件所依賴,assemblebase提供各個元件對外提供資料和方法調用的抽象service ,同時還有serviceFactory對service進行操作,各個元件在初始化的時候對各自的service進行實作。同時中也會提供所有的 Service 的空實作,以避免引起的空指針異常

就以登入子產品為例,對外提供兩個資料

public interface ILoginService {

    /**
     * 是否已經登入
     *
     * @return
     */
    boolean isLogin();

    /**
     * 擷取登入使用者的 AccountId
     *
     * @return
     */
    String getAccountId();

}
           

相關的serviceFactory類如下,可以通過serviceFactory拉取相關service的執行個體

public class ServiceFactory {

    private ILoginService loginService;
    private IGoodsService goodsService;

    /**
     * 禁止外部建立 ServiceFactory 對象
     */
    private ServiceFactory() {
    }

    /**
     * 通過靜态内部類方式實作 ServiceFactory 的單例
     */
    public static ServiceFactory getInstance() {
        return Inner.serviceFactory;
    }

    private static class Inner {
        private static ServiceFactory serviceFactory = new ServiceFactory();
    }

//    ------------------------LoginService------------------------
    /**
     * 接收 Login 元件實作的 Service 執行個體
     */
    public void setLoginService(ILoginService loginService) {
        this.loginService = loginService;
    }

    /**
     * 傳回 Login 元件的 Service 執行個體
     */
    public ILoginService getLoginService() {
        if (loginService == null) {
            loginService = new EmptyLoginService();
        }
        return loginService;
    }
           

在login元件中隻需要實作ILoginService,并通過serviceFactory進行設定

public class LoginService implements ILoginService {
    @Override
    public boolean isLogin() {
        return false;
    }

    @Override
    public String getAccountId() {
        return null;
    }
}
           

[圖檔上傳失敗…(image-4066c0-1627130966768)]

在login的appliction中進行service的設定

public class LoginApp extends BaseApp {

    @Override
    public void onCreate() {
        super.onCreate();
        initModuleApp(this);
        initModuleData(this);
    }

    @Override
    public void initModuleApp(Application application) {
        ServiceFactory.getInstance().setLoginService(new LoginService());
    }

    @Override
    public void initModuleData(Application application) {

    }
}
           

但是有這樣一個問題:在內建到app中,LoginApp是沒有被執行的,這個怎麼解決呢,我們可以通過反射進行解決

public class AssembleApplication extends BaseApp {
    @Override
    public void onCreate() {
        super.onCreate();
        initModuleApp(this);
        initModuleData(this);
        initComponentList();
    }

    @Override
    public void initModuleApp(Application application) {

    }

    @Override
    public void initModuleData(Application application) {

    }

    //初始化元件
    //通過反射初始化
    private void initComponentList(){
        for (String moduleApp : AppConfig.moduleApps) {
            try {
                Class clazz = Class.forName(moduleApp);
                BaseApp baseApp = (BaseApp) clazz.newInstance();
                baseApp.initModuleApp(this);
                baseApp.initModuleData(this);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}
           

如上所示就完成了

4:元件類(例如:Fragment)的擷取,以及誇元件頁面跳轉和通訊

fragment的擷取也是通過service來完成的

public interface IGoodsService {

    /**
     * 建立 GoodsFragment
     * @param bundle
     * @return
     */
    Fragment newGoodsFragment(Bundle bundle);
}
           

相關元件實作該接口就行

各個元件間頁面的跳轉可以通過阿裡的ARouter實作,我是通過設定ComponentName來實作的,但這種方式好像并沒有實作真正的代碼隔離

/**
     *
     * 去登陸
     *
     * 跨元件頁面跳轉
     */
    private void toLogin(){
        Intent intent = new Intent();
        intent.setComponent(new ComponentName(mContext, "ppzh.jd.com.login.LoginActivity"));
        startActivityForResult(intent,LOGIN_REQUEST_CODE);
    }
           

總結

通過上面就整體實作了項目元件化,在以後也可以更多的運用元件化來進行項目開發

最後

小編學習提升時,順帶從網上收集整理了一些 Android 開發相關的學習文檔、面試題、Android 核心筆記等等文檔,希望能幫助到大家學習提升,如有需要參考的可以直接去我 CodeChina位址:https://codechina.csdn.net/u012165769/Android-T3 通路查閱。

淺談 Android元件化概述子產品化群組件化元件化Demo總結