Androidコンポーネント化の予備調査[デモ付き]

デモアドレス:管理者を見つけるには、ここをクリックしてください

概要概要

ソフトウェア開発プロセスは、アーキテクチャの進化プロセスでもあります。例として、MVC、MVP、MVVPの最初からコンポーネント化、プラグイン化までのAndroidを取り上げますが、最終的な分析では、すべてがより良いメンテナンスのためのものです。プロジェクト。、開発コストを繰り返して削減します。

プロジェクトの開発プロセスでは、すべての機能モジュールを早い段階でまとめて、迅速な開発を実現する場合がありますが、プロジェクトが大きくなるにつれて、開発者と機能の数が増え、コードが増え、 、さまざまなモジュール間の結合がますます重くなり、全身に影響を及ぼしています。現時点では、プロジェクトの品質を確保するために、プロジェクトをリファクタリングする必要があります。

ビジネスモジュールごとにポイントをチェックし、異なるビジネスモジュールを異なるモジュールに配置し、各ビジネス間の構造を実現できます。また、基盤となる公共図書館に依存しています。これはモジュール性の概念ですが、複数のモジュールが含まれる場合同じ機能に到達すると、コードの結合が増加します。たとえば、ビデオ再生の機能を必要とするモジュールが2つあります。ビデオ再生を2つのコンポーネントに配置すると、コードの重複の問題が発生します。パブリックライブラリに配置しても問題は発生しません。とても気持ちがいいです。現時点では、コンポーネント化を使用してこの問題を解決してください

モジュール化とコンポーネント化

基本単位

製品詳細モジュール、製品リリースモジュール、検索モジュールなどの特定のビジネスモジュール

コンポーネント化

ビデオ再生コンポーネント、共有コンポーネントなどの単一機能コンポーネント。各コンポーネントは個別のモジュールとして開発でき、外部リリース用のSDKとして個別に抽出できます。

モジュール化とコンポーネント化の考え方は同じで、どちらもコードを分割することですが、モジュール化は機能モジュールに従ってチェックして分割することであり(ビジネス指向)、コンポーネント化は機能モジュールに従ってチェックして分割することです(モジュール化された粒子次数が大きく、コンポーネントの粒度が小さい。プロジェクト内にモジュールとコンポーネントが同時に存在することは非常に一般的であり、それらはそれぞれの業務に責任があります。

上の図に示すように、これはコンポーネント化されたプロジェクトの基本構造です。

  • 基本ライブラリ、パブリックライブラリ:プロジェクトに必要な基本操作クラス、ツールクラス、サードパーティライブラリインポートパッケージ、アプリホスト関数、各モジュール、各コンポーネントはすべてこのライブラリに依存しています
  • コンポーネントレイヤー:ログインモジュール、ビデオ再生コンポーネント、共有コンポーネントなど、プロジェクトで使用される機能モジュールまたはビジネスモジュール。
  • アプリケーション層:ホストプロジェクト、APPメインプロジェクト、APPエントランス、メインシェルフ

コンポーネント化されたデモ

デモアドレス:ここをクリックして、デモプロジェクトに基づいて次の側面から説明するように管理者に依頼してください

  • 1:プロジェクト分析
  • 2:コンポーネントアプリケーションとライブラリ間の動的切り替え
  • 3:コンポーネント間のデータ転送とメソッド呼び出し
  • 4:コンポーネントクラス(例:フラグメント)を取得し、コンポーネントページのジャンプと通信を自慢する

1:プロジェクト分析

上図に示すように、プロジェクトの主な構造

  • アプリケーション層:アプリプロジェクトのメインエントランス
  • コンポーネントレイヤー:商品ログイン製品詳細ページとログインコンポーネント
  • 基本ライブラリレイヤー:アセンブルベースは各コンポーネントのデータとメソッドを操作するために使用され、ベースは一般的に使用されるツールクラスであり、さまざまなクラスライブラリのパッケージです。

2:コンポーネントアプリケーションとライブラリ間の動的切り替え

開発プロセスでは、迅速な開発を実現するために、コンポーネントが独立して実行できることが特に重要です。Moudleは一般に2つのタイプに分けられます。

  • アプリプラグイン、ID:com.android.application
  • ライブラリ插件、id:com.android.library

構成を通じてアプリケーションとライブラリを動的に切り替えることができます。各コンポーネントのgradle.propertiesファイルで切り替えを制御する変数を構成します。

次に、build.gradleのisRunAlone変数を使用してアプリケーションとライブラリを切り替えることができます。3つの主要な設計ポイントがあります。

  • プラグイン属性の構成
  • 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'
            }
        }
    }

}

上記の構成を使用すると、アプリケーションとライブラリを切り替えることができます

3:コンポーネント間のデータ転送とメソッド呼び出し

メインプロジェクト、コンポーネント、コンポーネント、およびコンポーネントは、参照によってデータとメソッド呼び出しを直接渡すことができないため、開発プロセス中にデータとメソッド呼び出しを転送する方法は、「インターフェイス」+「実装」を介して実行できます。

アセンブルベースベースライブラリは、データ転送とメソッド呼び出しに使用されます。これはすべてのコンポーネントに依存します。アセンブルベースは、外部データとメソッド呼び出しを提供するために各コンポーネントに抽象サービスを提供します。同時に、サービスを操作するserviceFactoryもあります。 。各コンポーネントが初期化されます。それぞれのサービスを実装します。同時に、すべてのサービスのnull実装が提供され、次の原因によるnullポインター例外が回避されます。

ログインモジュールを例として取り上げ、2つの外部データを提供します

public interface ILoginService {

    /**
     * 是否已经登录
     *
     * @return
     */
    boolean isLogin();

    /**
     * 获取登录用户的 AccountId
     *
     * @return
     */
    String getAccountId();

}

関連するserviceFactoryクラスは次のとおりです。serviceFactoryを介して関連するサービスインスタンスをプルできます。

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;
    }

ログインコンポーネントにILoginServiceを実装し、serviceFactoryを介して設定するだけです。

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

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

ログインアプリケーションでサービスを設定します

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) {

    }
}

しかし、そのような問題があります:アプリに統合されたときに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:コンポーネントクラス(例:フラグメント)を取得し、コンポーネントページのジャンプと通信を自慢する

フラグメントの取得もサービスを通じて行われます

public interface IGoodsService {

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

関連コンポーネントはインターフェースを実装できます

さまざまなコンポーネント間のページジャンプは、AliのARouterを介して実現できます。ComponentNameを設定することで実現しましたが、このメソッドは実際のコード分離を実現していないようです。

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

総括する

以上により、プロジェクト全体としてのコンポーネント化が実現し、今後のプロジェクト開発にも活用できるようになります。

著者:ブラッドナゲッツ
は元のアドレスを保持しました:https://juejin.cn/post/6844903978036101128

やっと

この記事オープンソースプロジェクトに含まていますhttps//github.com/xieyuliang/Android-P7-share/blob/master/(青いフォントで表示するに
ここをクリック)、自己学習プログラミングルートとインタビューが含まれていますさまざまな方向への質問コレクション/フェイスクラシック、一連の技術記事など。リソースは継続的に更新されています...

おすすめ

転載: blog.csdn.net/weixin_49559515/article/details/111997332