依存性注入入門 依存性注入 (DI) は、依存性の作成と管理の制御がアプリケーションから外部エンティティに移される制御の反転 (IoC) を実装するために使用される設計パターンです。これにより、よりモジュール化され、テスト可能で、保守しやすいコードを作成できます。これは、オブジェクトの作成責任がコードの他の部分に転送される手法です。これにより疎結合が促進され、コードがよりモジュール化され、管理しやすくなります。 クラスが適切に機能するには、他のクラスへの参照が必要になることがよくあります。たとえば、 クラスを必要とする クラスを考えてみましょう。これらの必要なクラスは依存関係と呼ばれます。Library クラスは のインスタンスがないと動作しません。 Book Library Book Library クラスが必要なオブジェクトを取得するには、主に次の 3 つの方法があります。 : クラスは独自の依存関係を作成して初期化します。たとえば、 クラスは クラスの独自のインスタンスを作成し、初期化します。 自己構築 Library Book : クラスは外部ソースから依存関係を取得します。Context や などの一部の Android API は、このように動作します。 外部取得 Context getSystemService() : 依存性は、クラスが構築されるとき、または依存性を必要とするメソッドを通じてクラスに提供されます。たとえば、 コンストラクターは、 インスタンスをパラメーターとして受け取ります。 依存性の注入 Library Book 3 番目のオプションは依存性注入です。DI を使用すると、クラス インスタンスが依存関係を自ら取得するのではなく、クラスの依存関係を提供します。 依存性注入なしの例 DI がない場合、独自の 依存関係を作成する 次のようになります。 Book Library class Library { private Book book = new Book(); void open() { book.read(); } } public class Main { public static void main(String[] args) { Library library = new Library(); library.open(); } } これは、 クラスが独自の を構築するため、DI の例ではありません。次の理由で問題が発生する可能性があります。 Library Book : と 密結合されています。Library インスタンスは の 1 つのタイプを使用するため、サブクラスや代替実装を使用することが困難になります。 密結合 Library Book Library Book : への強い依存により、テストはより困難になります。 の実際のインスタンスを使用するため、異なるテスト ケースに合わせて を変更するテスト ダブルの使用が妨げられます。 テストの難しさ Book Library Book Book 依存性注入の例 DI を使用すると、 の各インスタンスが独自の オブジェクトを構築する代わりに、コンストラクターのパラメーターとして オブジェクトを受け取ります。 Library Book Book class Library { private Book book; Library(Book book) { this.book = book; } void open() { book.read(); } } public class Main { public static void main(String[] args) { Book book = new Book(); Library library = new Library(book); library.open(); } メイン関数は 使用します。Library に依存しているため、アプリは のインスタンスを作成し、それを使用して のインスタンスを構築します。この DI ベースのアプローチの利点は次のとおりです。 Library Library Book Book Library : のさまざまな実装を に渡すことができます。たとえば、 で使用する という の新しいサブクラスを定義するとします。DI を使用すると、 のインスタンスを に渡すだけで、それ以上の変更なしで動作します。 Library の再利用性 Book Library Library EBook Book EBook Library : テスト ダブルを渡してさまざまなシナリオをテストできます。 Library の簡単なテスト 別の DI の例 クラスが クラスに依存するシナリオを考えてみましょう。DI がない場合、 は のインスタンスを直接作成するため、異なるタイプの通知を使用したり、さまざまな通知実装でサービスをテストしたりすることが難しくなります。 NotificationService Notification NotificationService Notification DI を説明するために、この例をリファクタリングしてみましょう。 interface Notification { void send(); } class EmailNotification implements Notification { @Override public void send() { // Send email notification } } class SMSNotification implements Notification { @Override public void send() { // Send SMS notification } } class NotificationService { void sendNotification(Notification notification) { notification.send(); } } 現在、 特定のクラスではなく インターフェースに依存しています。これにより、 のさまざまな実装を相互に使用できます。使用する実装は、 メソッドを通じて設定できます。 NotificationService Notification Notification sendNotification NotificationService service = new NotificationService(); service.sendNotification(new EmailNotification()); service.sendNotification(new SMSNotification()); Android における依存性注入の方法 DI には主に 3 つのタイプがあります。 : 依存関係は、クラスがインターフェースまたは別のクラスを介してアクセスできるメソッドを通じて渡されます。前の例は、メソッド インジェクションを示しています。 メソッド (インターフェース) インジェクション : 依存関係はコンストラクターを通じてクラスに渡されます。 コンストラクター インジェクション class NotificationService { private final Notification notification; public NotificationService(Notification notification) { this.notification = notification; } public void sendNotification() { notification.send(); } } public class Main { public static void main(String[] args) { NotificationService service = new NotificationService(new EmailNotification()); service.sendNotification(); } } : アクティビティやフラグメントなどの特定の Android フレームワーク クラスはシステムによってインスタンス化されるため、コンストラクター インジェクションは不可能です。フィールド インジェクションでは、クラスの作成後に依存関係がインスタンス化されます。 3. フィールド インジェクション (またはセッター インジェクション) class NotificationService { private Notification notification; public Notification getNotification() { return notification; } public void setNotification(Notification notification) { this.notification = notification; } public void sendNotification() { notification.send(); } } public class Main { public static void main(String[] args) { NotificationService service = new NotificationService(); service.setNotification(new EmailNotification()); service.sendNotification(); } } : 依存関係はメソッドを通じて提供され、多くの場合 アノテーションが使用されます。 4. メソッド インジェクション @Inject 依存性注入の利点 クラスの再利用性が向上し、特定の実装への依存度が低くなります。これは制御の反転によるもので、クラスは依存関係を管理せず、提供された任意の構成で動作するようになります。 依存関係は API サーフェスの一部であり、オブジェクトの作成時またはコンパイル時に検証できるため、リファクタリングが容易になります。 クラスは依存関係を管理しないため、さまざまなシナリオをカバーするためにテスト中にさまざまな実装を渡すことが可能です。 自動化された依存性注入 前の例では、ライブラリを使用せずに、さまざまなクラスの依存関係を手動で作成、提供、管理しました。このアプローチは、手動の依存関係の注入と呼ばれます。単純なケースでは機能しますが、依存関係とクラスの数が増えると面倒になります。手動の依存関係の注入には、いくつかの欠点があります。 : 大規模なアプリケーションでは、すべての依存関係を管理し、それらを正しく接続すると、多くの繰り返しコードが発生する可能性があります。多層アーキテクチャでは、最上位層のオブジェクトを作成するには、その下の層のすべての依存関係を提供する必要があります。たとえば、コンピューターを構築するには、CPU、マザーボード、RAM、およびその他のコンポーネントが必要です。CPU には、トランジスタとコンデンサが必要になる場合があります。 定型コード : 遅延初期化や、アプリ内の特定のフローにオブジェクトのスコープを設定するなど、事前に依存関係を構築できない場合は、カスタム コンテナー (または依存関係グラフ) を作成して維持し、メモリ内の依存関係の有効期間を管理する必要があります。 複雑な依存関係の管理 ライブラリは依存関係を作成して提供することで、このプロセスを自動化できます。これらのライブラリは、次の 2 つのカテゴリに分類されます。 : 実行時に依存関係を接続します。 リフレクションベースのソリューション : コンパイル時に依存関係を接続するコードを生成します。 静的ソリューション Dagger は、Google が管理する Java、Kotlin、Android 向けの人気の依存性注入ライブラリです。Dagger は依存性グラフを作成および管理することで、アプリの DI を簡素化します。完全に静的なコンパイル時の依存性を提供し、Guice などのリフレクション ベースのソリューションに関連する開発およびパフォーマンスの問題の多くに対処します。 リフレクションベースのソリューション これらのフレームワークは実行時に依存関係を接続します。 : リフレクションを使用して依存関係を接続するランタイム DI フレームワーク。軽量かつ高速に設計されており、Android アプリケーションに適しています。 Toothpick 静的ソリューション これらのフレームワークは、コンパイル時に依存関係を接続するコードを生成します。 : Dagger 上に構築された Hilt は、Android アプリケーションに Dagger 依存性注入を組み込む標準的な方法を提供します。 。 Hilt 定義済みのコンポーネントとスコープを提供することで、Dagger のセットアップと使用を簡素化します : Kotlin 用の軽量でシンプルな DI フレームワーク。Koin は DSL を使用して依存関係を定義し、セットアップと使用が簡単です。 Koin : 使いやすく理解しやすい Kotlin ベースの DI フレームワーク。依存関係を管理するためのシンプルで柔軟な API を提供します。 Kodein 依存性注入の代替 依存性注入の代替として、サービス ロケーター パターンがあります。この設計パターンは、クラスを具体的な依存性から分離するのにも役立ちます。依存性を作成して保存し、必要に応じて提供する、サービス ロケーターと呼ばれるクラスを作成します。 object ServiceLocator { fun getProcessor(): Processor = Processor() } class Computer { private val processor = ServiceLocator.getProcessor() fun start() { processor.run() } } fun main(args: Array<String>) { val computer = Computer() computer.start() } サービス ロケーター パターンは、依存関係の使用方法において依存性の注入とは異なります。サービス ロケーター パターンでは、クラスが必要な依存関係を要求しますが、依存性の注入では、アプリが必要なオブジェクトを積極的に提供します。 Dagger 2とは何ですか? Dagger 2 は、Android 向けの人気の DI フレームワークです。コンパイル時のコード生成を使用し、高いパフォーマンスで知られています。Dagger 2 は、依存関係を処理するために必要なコードを生成することで依存性注入のプロセスを簡素化し、定型句を減らして効率を向上させます。 Dagger 2 は、Android での依存性注入のためのアノテーションベースのライブラリです。主なアノテーションとその目的は次のとおりです。 : 依存関係を提供するクラスを定義するために使用されます。たとえば、モジュールは Retrofit 用の を提供できます。 @Module ApiClient : モジュール内のメソッドに注釈を付けて、依存関係を作成して返す方法を指定します。 @Provides : 依存関係を要求するために使用されます。フィールド、コンストラクター、メソッドに適用できます。 @Inject : と を橋渡しするインターフェース。すべてのモジュールが含まれ、アプリケーションのビルダーを提供します。 @Component @Module @Inject : 依存関係の単一のインスタンスが作成されるようにします。 @Singleton : 依存関係を提供するために抽象クラスで使用されます。 に似ていますが、より簡潔です。 @Binds @Provides ダガーコンポーネント Dagger はプロジェクトの依存関係グラフを生成し、必要に応じて依存関係を取得する場所を決定できます。これを有効にするには、インターフェースを作成し、 で注釈を付ける必要があります。 @Component インターフェース内で、必要なクラス (例: ) のインスタンスを返すメソッドを定義します。 アノテーションは、Dagger が公開する型を満たすために必要なすべての依存関係を含むコンテナーを生成するように Dagger に指示します。このコンテナーは Dagger コンポーネントと呼ばれ、Dagger が提供できるオブジェクトのグラフとその依存関係が含まれています。 @Component BookRepository @Component 例 に関する例を考えてみましょう。 LibraryRepository : コンストラクターに 注釈を追加して、Dagger が のインスタンスを作成する方法を認識できるようにします。 コンストラクターに注釈を付ける LibraryRepository @Inject LibraryRepository public class LibraryRepository { private final LocalLibraryDataSource localDataSource; private final RemoteLibraryDataSource remoteDataSource; @Inject public LibraryRepository(LocalLibraryDataSource localDataSource, RemoteLibraryDataSource remoteDataSource) { this.localDataSource = localDataSource; this.remoteDataSource = remoteDataSource; } } : 同様に、依存関係のコンストラクター ( および ) に注釈を付けて、Dagger が依存関係の作成方法を認識できるようにします。 2. 依存関係に注釈を付ける LocalLibraryDataSource RemoteLibraryDataSource public class LocalLibraryDataSource { @Inject public LocalLibraryDataSource() { // Initialization code } } public class RemoteLibraryDataSource { private final LibraryService libraryService; @Inject public RemoteLibraryDataSource(LibraryService libraryService) { this.libraryService = libraryService; } } : 依存関係グラフを定義するために、 アノテーションが付けられたインターフェースを作成します。 3. コンポーネントを定義する @Component @Component public interface ApplicationComponent { LibraryRepository getLibraryRepository(); } プロジェクトをビルドすると、Dagger によって、通常は という名前の インターフェースの実装が生成されます。 DaggerApplicationComponent ApplicationComponent 使用法 生成されたコンポーネントを使用して、依存関係が自動的に注入されたクラスのインスタンスを取得できるようになりました。 public class MainApplication extends Application { private ApplicationComponent applicationComponent; @Override public void onCreate() { super.onCreate(); applicationComponent = DaggerApplicationComponent.create(); } public ApplicationComponent getApplicationComponent() { return applicationComponent; } } アクティビティまたはフラグメントでは、 インスタンスを取得できます。 LibraryRepository public class MainActivity extends AppCompatActivity { @Inject LibraryRepository libraryRepository; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ((MainApplication) getApplication()).getApplicationComponent().inject(this); // Use the injected libraryRepository } } Dagger 2 の主要概念 1. モジュール ∘ モジュールの主要概念 ∘ コンポーネントにモジュールを含める 2. スコープ 3. コンポーネント 4. コンポーネントの依存関係 5. ランタイムバインディング 1. モジュール Dagger 2 のモジュールは、コンポーネントに依存関係を提供する アノテーションが付けられたクラスです。モジュールには、依存関係の作成方法と提供方法を指定するために または アノテーションが付けられたメソッドが含まれています。モジュールは、アプリケーションに必要なオブジェクトの作成を整理および管理するために不可欠です。 @Module @Provides @Binds モジュールの主要概念 @Module アノテーション: このアノテーションは、クラスを Dagger モジュールとして定義するために使用されます。モジュール クラスには、依存関係を提供するメソッドが含まれています。 @Provides アノテーション: このアノテーションは、モジュール内のメソッドで使用され、メソッドが特定の依存関係を提供することを示します。これらのメソッドは、依存関係のインスタンスを作成して返す役割を担います。 @Binds アノテーション: このアノテーションは、抽象クラスで実装をインターフェースにバインドするために使用されます。これは よりも簡潔で、モジュールが抽象クラスの場合に使用されます。 @Provides モジュールの例 @Module public class NetworkModule { @Provides @Singleton Retrofit provideRetrofit() { return new Retrofit.Builder() .baseUrl("https://api.example.com") .addConverterFactory(GsonConverterFactory.create()) .build(); } @Provides @Singleton OkHttpClient provideOkHttpClient() { return new OkHttpClient.Builder() .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) .build(); } } この例では、 アノテーションが付けられたクラスです。このクラスには、 と のインスタンスを作成して返す、 アノテーションが付けられた 2 つのメソッドが含まれています。 NetworkModule @Module Retrofit OkHttpClient @Provides @Binds の使用 インターフェースとその実装がある場合は、 を使用して実装をインターフェースにバインドできます。これは、 を使用するよりも簡潔です。 @Binds @Provides public interface ApiService { void fetchData(); } public class ApiServiceImpl implements ApiService { @Override public void fetchData() { // Implementation } } @Module public abstract class ApiModule { @Binds abstract ApiService bindApiService(ApiServiceImpl apiServiceImpl); } この例では、 アノテーションが付けられた抽象クラスです。bindApiService メソッドには アノテーションが付けられ、 バインドします。 ApiModule @Module @Binds ApiServiceImpl bindApiService ApiService モジュールは、提供する機能に基づいて整理できます。たとえば、ネットワーク操作、データベース操作、UI 関連の依存関係ごとに個別のモジュールを用意できます。 例: : や などのネットワーク関連の依存関係を提供します。 NetworkModule Retrofit OkHttpClient : のようなデータベース関連の依存関係を提供します。 DatabaseModule RoomDatabase : や などの UI 関連の依存関係を提供します。 UIModule ViewModel Presenter コンポーネントにモジュールを含める モジュールは、それを必要とするクラスに依存関係を提供するためにコンポーネントに含まれています。設定方法は次のとおりです。 アプリケーションコンポーネント.java: @Singleton @Component(modules = {NetworkModule.class, DatabaseModule.class}) public interface ApplicationComponent { void inject(MyApplication application); } この例では、 には、アプリケーションへの依存関係を提供するために と が含まれています。 ApplicationComponent NetworkModule DatabaseModule 2. スコープ Dagger 2 のスコープは、依存関係のライフサイクルを定義する注釈です。スコープにより、依存関係の単一のインスタンスが指定されたスコープ内で作成され、共有されることが保証されます。これにより、メモリを効率的に管理し、依存関係が適切な場所で再利用されることが保証されます。 : アプリケーションのライフサイクル全体を通じて依存関係のインスタンスが 1 つだけであることを保証します。 シングルトン スコープ : アクティビティのライフサイクル内で依存関係のインスタンスが 1 つだけであることを保証します。 アクティビティ スコープ : フラグメントのライフサイクル内で依存関係のインスタンスが 1 つだけであることを保証します。 フラグメント スコープ 1. シングルトンスコープ : スコープは、依存関係の単一のインスタンスが作成され、アプリケーションのライフサイクル全体を通じて共有されることを保証します。 定義 @Singleton このスコープは通常、ネットワーク クライアント、データベース インスタンス、共有設定など、アプリケーション全体で共有する必要がある依存関係に使用されます。 例: @Singleton @Component(modules = {NetworkModule.class, DatabaseModule.class}) public interface ApplicationComponent { void inject(MyApplication application); } この例では、 アノテーションにより、 および によって提供される インスタンスと インスタンスがシングルトンであり、アプリケーション全体で共有されることが保証されます。 @Singleton NetworkModule DatabaseModule Retrofit Database 2. 活動範囲 : (カスタム スコープ) は、アクティビティのライフサイクル内で依存関係の単一インスタンスが作成され、共有されることを保証します。 定義 @ActivityScope このスコープは、プレゼンターやビュー モデルなど、アクティビティに固有で、アクティビティが再作成されるたびに再作成する必要がある依存関係に役立ちます。 : 例 @Scope @Retention(RetentionPolicy.RUNTIME) public @interface ActivityScope { } @ActivityScope @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity mainActivity); } この例では、 アノテーションにより、 によって提供される依存関係がアクティビティのライフサイクルにスコープされることが保証されます。 @ActivityScope ActivityModule 3. フラグメントスコープ : (別のカスタム スコープ) は、フラグメントのライフサイクル内で依存関係の単一のインスタンスが作成され、共有されることを保証します。 定義 @FragmentScope 使用例: このスコープは、フラグメント固有のプレゼンターやビュー モデルなど、フラグメントが再作成されるたびに再作成する必要がある、フラグメントに固有の依存関係に役立ちます。 : 例 @Scope @Retention(RetentionPolicy.RUNTIME) public @interface FragmentScope { } @FragmentScope @Component(dependencies = ActivityComponent.class, modules = FragmentModule.class) public interface FragmentComponent { void inject(MyFragment myFragment); } この例では、 アノテーションにより、 によって提供される依存関係がフラグメントのライフサイクルにスコープされることが保証されます。 @FragmentScope FragmentModule 3. コンポーネント コンポーネントの依存関係により、あるコンポーネントが別のコンポーネントに依存することが可能になり、依存関係の再利用が可能になります。コンポーネントの依存関係には、主に次の 2 つの種類があります。 : アプリケーション全体に必要な依存関係を提供します。 アプリケーション コンポーネント : 特定のアクティビティ内で必要な依存関係を提供します。 アクティビティ コンポーネント 1. アプリケーションコンポーネント : アプリケーション コンポーネントは、アプリケーション全体で必要な依存関係を提供します。通常は、依存関係がアプリケーション全体で共有されるように、 でスコープ設定されます。 定義 @Singleton このコンポーネントは、ネットワーク クライアント、データベース インスタンス、共有設定など、グローバルに使用可能にする必要がある依存関係に使用されます。 : 例 @Singleton @Component(modules = {NetworkModule.class, DatabaseModule.class}) public interface ApplicationComponent { void inject(MyApplication application); } この例では、 、アプリケーション全体で共有される インスタンスと インスタンスを提供する役割を担っています。 ApplicationComponent Retrofit Database 2. アクティビティコンポーネント : アクティビティ コンポーネントは、特定のアクティビティ内で必要な依存関係を提供します。通常、アクティビティが再作成されるたびに依存関係が再作成されるように、 などのカスタム スコープでスコープ設定されます。 定義 @ActivityScope このコンポーネントは、プレゼンターやビュー モデルなど、アクティビティに固有の依存関係に使用されます。 : 例 @ActivityScope @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity mainActivity); } この例では、 に依存し、 に固有の依存関係を提供します。 ActivityComponent ApplicationComponent MainActivity 4. コンポーネントの依存関係 コンポーネントの依存関係により、あるコンポーネントが別のコンポーネントに依存することが可能になり、依存関係の再利用が可能になります。コンポーネントの依存関係には、主に次の 2 つの種類があります。 : サブコンポーネントは別のコンポーネントの子であり、親の依存関係にアクセスできます。 サブコンポーネント : これにより、コンポーネントはサブコンポーネントにならずに別のコンポーネントに依存できるようになります。 依存属性 1. サブコンポーネント: サブコンポーネントは別のコンポーネントの子であり、親の依存関係にアクセスできます。サブコンポーネントは親コンポーネント内で定義され、そのスコープを継承できます。 : 例 @ActivityScope @Subcomponent(modules = ActivityModule.class) public interface ActivitySubcomponent { void inject(MainActivity mainActivity); } この例では、 親コンポーネントのサブコンポーネントであり、その依存関係にアクセスできます。 ActivitySubcomponent 2. 依存属性 これにより、コンポーネントはサブコンポーネントにならずに別のコンポーネントに依存できるようになります。依存コンポーネントは、親コンポーネントによって提供される依存関係にアクセスできます。 : 例 @ActivityScope @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity mainActivity); } この例では、 に依存しており、その依存関係にアクセスできます。 ActivityComponent ApplicationComponent 5. ランタイムバインディング Dagger 2 のランタイム バインディングとは、必要なコンテキストに基づいて実行時に作成および管理される依存関係の提供を指します。 : アプリケーションと同じ期間存続する必要がある依存関係に使用されます。 アプリケーション コンテキスト : アクティビティと同じ期間存続する必要がある依存関係に使用されます。 アクティビティ コンテキスト 1. アプリケーションのコンテキスト : アプリケーション コンテキストは、アプリケーション全体のライフサイクルに関連付けられたコンテキストです。アプリケーション自体と同じ期間存続する必要がある依存関係に使用されます。 定義 アプリケーション全体で共有され、アクティビティやフラグメントごとに再作成する必要のない依存関係。例としては、ネットワーク クライアント、データベース インスタンス、共有設定などがあります。 : 例 @Module public class AppModule { private final Application application; public AppModule(Application application) { this.application = application; } @Provides @Singleton Application provideApplication() { return application; } @Provides @Singleton Context provideApplicationContext() { return application.getApplicationContext(); } } この例では、 アプリケーション コンテキストをシングルトン依存関係として提供します。provideApplicationContext メソッドは、提供されるコンテキストがアプリケーションのライフサイクルに関連付けられていること 保証します。 AppModule provideApplicationContext 2. アクティビティのコンテキスト : アクティビティ コンテキストは、特定のアクティビティのライフサイクルに関連付けられたコンテキストです。アクティビティ自体と同じ期間存続する必要がある依存関係に使用されます。 定義 アクティビティに固有の依存関係であり、アクティビティが再作成されるたびに再作成する必要があります。例としては、ビュー モデル、プレゼンター、UI 関連の依存関係などがあります。 : 例 @Module public class ActivityModule { private final Activity activity; public ActivityModule(Activity activity) { this.activity = activity; } @Provides @ActivityScope Activity provideActivity() { return activity; } @Provides @ActivityScope Context provideActivityContext() { return activity; } } この例では、 アクティビティ コンテキストをスコープ指定された依存関係として提供します。provideActivityContext メソッドは、提供されたコンテキストがアクティビティのライフサイクルに関連付けられていること 保証します。 ActivityModule provideActivityContext コンポーネントでのランタイムバインディングの使用 これらのランタイム バインディングを使用するには、コンポーネントに対応するモジュールを含める必要があります。 : アプリケーションコンポーネント @Singleton @Component(modules = {AppModule.class, NetworkModule.class}) public interface ApplicationComponent { void inject(MyApplication application); Context getApplicationContext(); } : アクティビティコンポーネント @ActivityScope @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity mainActivity); Context getActivityContext(); } コンテキストの挿入 コンポーネントとモジュールを設定したら、必要に応じてコンテキストをクラスに挿入できます。 : アクティビティの例 public class MainActivity extends AppCompatActivity { @Inject Context activityContext; @Inject Context applicationContext; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ApplicationComponent appComponent = ((MyApplication) getApplication()).getApplicationComponent(); ActivityComponent activityComponent = DaggerActivityComponent.builder() .applicationComponent(appComponent) .activityModule(new ActivityModule(this)) .build(); activityComponent.inject(this); // Use the injected contexts Log.d("MainActivity", "Activity Context: " + activityContext); Log.d("MainActivity", "Application Context: " + applicationContext); } } この例では、 依存性の注入を通じてアクティビティ コンテキストとアプリケーション コンテキストの両方を受け取ります。これにより、アクティビティは依存性の特定のニーズに基づいて適切なコンテキストを使用できるようになります。 MainActivity 例: Android アプリケーションで Dagger 2 を使用する ダガー2の設定 プロジェクトで Dagger 2 を使用するには、 ファイルに次の依存関係を追加する必要があります。 build.gradle dependencies { implementation 'com.google.dagger:dagger:2.x' annotationProcessor 'com.google.dagger:dagger-compiler:2.x' } を Dagger 2 の最新バージョンに置き換えます。 2.x ステップ1: モジュールを定義する 依存関係を提供するモジュールを作成します。たとえば、 インスタンスを提供する 次のようになります。 Retrofit NetworkModule @Module public class NetworkModule { @Provides @Singleton Retrofit provideRetrofit() { return new Retrofit.Builder() .baseUrl("https://api.example.com") .addConverterFactory(GsonConverterFactory.create()) .build(); } } ステップ2: コンポーネントを定義する モジュールと依存関係を必要とするクラスをブリッジするコンポーネントを作成します。 @Singleton @Component(modules = {NetworkModule.class}) public interface ApplicationComponent { void inject(MyApplication application); } ステップ3: 依存関係を注入する コンポーネントを使用してクラスに依存関係を挿入します。たとえば、 クラスでは次のようになります。 Application public class MyApplication extends Application { private ApplicationComponent applicationComponent; @Override public void onCreate() { super.onCreate(); applicationComponent = DaggerApplicationComponent.builder() .networkModule(new NetworkModule()) .build(); applicationComponent.inject(this); } public ApplicationComponent getApplicationComponent() { return applicationComponent; } } ステップ4: 注入された依存関係を使用する これで、注入された依存関係をクラスで使用できるようになります。たとえば、 では次のようになります。 Activity public class MainActivity extends AppCompatActivity { @Inject Retrofit retrofit; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ((MyApplication) getApplication()).getApplicationComponent().inject(this); // Use the injected Retrofit instance // ... } } 結論 このトピックを要約してみましょう: DI の主なポイントは、結合を緩め、依存関係を管理しやすくすることです。 DI を使用すると、コードの柔軟性が向上し、テスト プロセスが簡素化されます。 DI は、シナリオに基づいてさまざまな実装が行われる複雑なトピックです。 さまざまな言語の DI には、操作方法に影響を与える可能性のある特殊性があります。 Dagger 2 は依存関係の作成と提供のプロセスを自動化し、定型コードを削減して保守性を向上させます。 Dagger 2 はコンパイル時の安全性を提供し、アプリケーションの実行前にすべての依存関係が満たされることを保証します。 Dagger 2 はコンパイル時にコードを生成することで、リフレクション ベースのソリューションに関連するパフォーマンスのオーバーヘッドを回避します。