PS:あなたが今頑張っていることは、現在は何の効果もないかもしれませんが、将来のある時点で役に立つことを示しているわけではありません。
アプリプロジェクトが一定の複雑さに達すると、プロジェクトのコンポーネント化は不可欠です。コンポーネント化は機能の分割をより良く行うことができます。コンポーネント化というと、モジュール化を思い浮かべる人もいるかもしれませんが、実際にはコンポーネント化とモジュール化の本質は同じで、どちらもコードの再利用とビジネスのデカップリングを目的としています。モジュール化は主にビジネスに基づいて分割され、コンポーネント化は主に機能に基づいて分割されます。コンポーネント化の最も基本的な側面からコンポーネント化の扉を開きます。
- コンポーネント間のジャンプ
- 動的作成
- リソースの競合
- 静的定数
コンポーネント間のジャンプ#
コンポーネント化において、2 つの機能モジュールは直接依存していません。その依存ルールは、Base module を介して間接的に依存します。コンポーネント間の Activity が画面遷移を行う際、相互依存関係がないため、別のモジュールの Activity を参照できないことがよくあります。
暗黙のジャンプ#
暗黙のジャンプは、Android のネイティブ Intent マッチングメカニズムを使用して実現されます。これは、Action を使用して対応する Activity にジャンプすることです。このように暗黙のジャンプを使用することで、モジュールを越えて Activity 間のジャンプが可能になります。注意点として、Activity が存在するモジュールから移動し、対応するジャンプを移動しない場合、引き続きジャンプを行うと例外が発生します。暗黙の Intent でジャンプする場合は、その Intent を受け取るアプリケーションがあるかどうかを確認する必要があります。そのためには、resolveActivity () メソッドを呼び出して、少なくとも 1 つのアプリケーションがその Intent を処理できるかどうかを判断します。また、暗黙のジャンプの方法では、exported を false に設定して、自分のアプリだけが対応するコンポーネントを起動できるようにすることもできます。
ARouter ジャンプ#
Android 開発において、モジュールは異なるネットワークと見なすことができ、対応する Router は各モジュールを接続する中継地点です。この中継地点は、ページ遷移のパラメータなどを統一的に処理できます。ARouter はアリババがオープンソースしたページ遷移ルーティングで、ARouter を使用することで暗黙のジャンプを置き換え、異なるモジュールや異なるコンポーネント間のジャンプ、およびジャンププロセスのリスニング、パラメータの伝達などを実現できます。ARouter はパスジャンプと URL ジャンプの 2 つの方法をサポートしており、使用も非常に柔軟です。ARouter の具体的な使用法についてはここでは紹介しませんが、詳細は別の記事で説明します。ARouter と Android の従来のジャンプ方法の比較は以下の通りです。
- 明示的なジャンプはクラスに依存する必要がありますが、ルーティングジャンプは指定されたパスでジャンプします。
- 暗黙のジャンプは AndroidManifest で集中管理され、協力開発が困難になります。
- ネイティブは AndroidManifest を使用して登録しますが、ルーティングはアノテーションで登録します。
- ネイティブの startActivity の後、ジャンププロセスは Android システムによって制御されますが、ルーティングジャンプは AOP アスペクト指向プログラミングを使用してジャンププロセスをインターセプトおよびフィルタリングします。
動的作成#
コンポーネント化開発において最も重要な点は、各モジュールや各コンポーネント間のデカップリングをできるだけ進めることです。これにより、Java のリフレクションメカニズムを使用することを考えることが容易になります。リフレクションを使用すると、実行時に特定のクラスのすべての情報を取得でき、そのクラスの属性やメソッドを動的に操作できます。Fragment が単独のコンポーネントとして使用される場合、この Fragment コンポーネントが移動する必要がないとき、通常の Fragment ではその Fragment をインデックスできず、アプリがクラッシュします。リフレクションを使用して Fragment を作成する方法を考えると、少なくともアプリのクラッシュを引き起こすことはありません。ここで例外をキャッチして関連するロジックを完了することができ、これにより耦合が低下するのではないでしょうか。リフレクションには一定のパフォーマンスの問題がありますが、リフレクションを使用することで、ある程度耦合を低下させることができることがわかります。コンポーネント化における Java のリフレクションメカニズムを学ぶことは必須の一部であるべきです。
コンポーネント化開発では、各コンポーネントが独立して実行できることが求められます。一般的に、各コンポーネントには一定の初期化手順があります。最良の状況は、プロジェクトに必要な複数のコンポーネントの初期化が基本的に同じであることです。その場合、初期化を BaseModule に統一して行うことができます。しかし、この状況は理想的なものであり、一般的には各コンポーネントの初期化は異なります。各自の Application で初期化を行うことを考えるかもしれませんが、各自の Application で初期化を行うと、最終的なコンパイル時に Application のマージにより問題が発生することは避けられません。この方法も好ましくありません。ここで再びリフレクションを考え、各コンポーネントに初期化ファイルを作成し、最終的な Application でリフレクションを使用して各コンポーネントの初期化操作を完了します。ここで Java のリフレクションメカニズムを使用して、コンポーネント化開発における Application の動的構成を実現しました。
リソースの競合#
コンポーネント化開発の過程で、ModuleA の AndroidManifest ファイルで android属性を使用して対応する Application を指定し、主 App Module の AndroidManifest ファイルでも android属性を使用して対応する Application を指定した場合、主 App Moduleの AndroidManifest ファイルで tools="android" を使用して競合を解決する必要があります。replace 属性を使用することで、タグの下の android属性がコンパイル時に置き換えられることを示します。したがって、AndroidManifest ファイルの置き換えルールに基づいて、最終的に指定される Application は App Module 内の指定された Application である必要があります。
例えば、プロジェクトの特定の機能モジュールで SMSSDK を使用して SMS 認証機能を実現した場合、他の場所では使用しないため、使用する機能モジュールにのみ導入しました。他のモジュールで使用する場合は、SMSSDK を BaseModule に導入する必要があります。SMSSDK を使用する際にそのモジュールの Application を指定しないと、MobSDK は com.mob.MobApplication をそのモジュールの Application として指定します。この場合、全体のコンパイルパッケージ時に AndroidManifest ファイルの android属性の競合が発生します。もちろん、解決方法は replace 属性を使用することです。AndroidManifest ファイルのマージ後の主な競合はこの問題です。もちろん、の他の属性に競合がある場合も、replace 属性を使用します。実際の開発では、検証を多く行うことでより多くの成果を得ることができます。
コンポーネント化開発において、もう 1 つ注意が必要なのは、リソース名が同じであることによって最終的なマージ時に競合が発生し、リソースの参照エラーや特定のリソースの喪失などが起こることです。文字列、色値などのリソースがマージ時に後から読み込まれた同じ名前のリソースによって置き換えられることがあります。この問題を解決するための考え方は、リソース命名に一定のルールを持たせることです。build.gradle ファイルで "resourcePrefix" コンポーネント名 ""の形式で開発者にリソース名の一意性を強制することをお勧めします。モジュール内のリソースの命名形式は"Module 名_機能_その他 " とすることをお勧めします。
静的定数#
コンポーネント化開発において、最終的なマージ時に各コンポーネントは Lib Module の形式で存在しますが、Lib Module 内の R.java ファイルで定義された静的変数が final として宣言されていない場合、対応する定数をコンポーネントモジュール内で使用できなくなります。例えば、switch 文を使用できなくなります。これにより、コンポーネント内では if 文を使用する必要があります。もちろん、コンポーネントが独立して実行される場合にはこの問題はありません。
開発中によく Butterknife を使用します。Butterknife は View や View のイベントなどに対して非常に便利にアノテーション操作を行うことができます。これはコンパイル時アノテーションメカニズムを採用しており、アノテーション内では定数のみを使用できます。したがって、Butterknife をコンポーネント化開発で使用する場合は、R の代わりに R2 を使用する必要があります。R2 は実際には R のコピーであり、R2 に対応する変数は final として宣言されています。したがって、コンポーネント化開発で Butterknife を使用する場合は、対応するアノテーション内で R2 を R の代わりに使用する必要があります。次回は Application のコンポーネント化について紹介します。