Dagger 2.11およびAndroid。 パート2

前の記事で 、特別なdagger-androidモジュールを使用して、アクティビティとフラグメントの依存関係、および異なるスコープの構成を提供する方法を検討しました。


この記事では、モジュールのコンポーネントを検討し、Androidの他の基本コンポーネントでの依存関係の提供を検討し、動的パラメーターで依存関係を提供するためのオプションも検討します。


dagger-androidモジュールを使用すると、次の基本的なAndroidコンポーネントに依存関係を注入できます。


Activity, Fragment, Service, DaggerIntentService, BroadcastReceiver, ContentProvider.


サポートライブラリのクラス( AppCompatActivity, android.support.v4.app.Fragment )を使用する場合、追加のダガーサポートライブラリ(dagger-android-support)の対応するクラスを使用する必要があります。


AndroidInjector


基本コンポーネント( Activity, Fragment, .. )の継承者に依存関係を注入します。


@ContributesAndroidInjector


この注釈は、モジュールの抽象メソッドに適用する必要があります。メソッドの戻り値の型は、基本的なandroidコンポーネント( Activity, Fragment .. )の相続人です。 メソッドにパラメーターを含めることはできません。


このアノテーションは、アノテーションが示されているメソッドの戻り値の型のAndroidInjectorを生成するために使用されます。 このAndroidInjectorはサブコンポーネントです。 このサブコンポーネントは、このモジュール(このアノテーションが存在する)が追加されるコンポーネント(またはサブコンポーネント)の子です。


注釈には、 modulesパラメーターが含まれています。 このパラメーターは、この生成されたサブコンポーネントに追加されるモジュールを示します。


アノテーション@ContributesAndroidInjector持つメソッドの上@ContributesAndroidInjectorアノテーションも存在@ContributesAndroidInjectorあります。 このスコープは、生成されたサブコンポーネントに適用されます。


AndroidInjectionModule / AndroidSupportInjectionModule


組み込みの短剣アンドロイドライブラリモジュール。 ルートコンポーネントに追加する必要があります。
@ContributesAndroidInjectorアノテーションを使用して生成されたサブコンポーネントを作成するためのファクトリーを備えたコレクションの複数の組み合わせが含まれています。 Androidの各基本コンポーネントには、独自のコレクションがあります。


AndroidInjectorのディスパッチ


これはAndroidInectorプロキシであり、特定のタイプのサブコンポーネント( AndroidInjector )を作成するためのファクトリーのコレクションが含まれています。 たとえば、 DispatchingAndroidInjector<Activity>は、 Activity継承者のすべてのサブコンポーネント作成ファクトリが含まれます。 注入するとき、目的のファクトリを検索し、サブコンポーネント( AndroidInject )を作成し、依存関係を注入します。


AndroidInjection / AndroidSupportInjection


ユーティリティクラスには、すべてのベースタイプ( Activity, Fragment, Service .. )に対してオーバーロードされたinjectメソッドがあります。 渡されたタイプに応じて、次のインターフェースのいずれかの実装を検索します。



短剣アンドロイドサポート



目的のAndroidInjectを含む目的のインターフェイスの実装の検索は、ライフタイムが長いオブジェクトで行われます。
HasActivityInjector, HasServiceInjector, HasContentProviderInjector, HasBroadcastReceiverInjector各インターフェイスをアプリケーションに実装する必要があります。 HasFragmentInjectorまたはHasSupportFragmentInjectorは、フラグメントまたはアクティビティまたはapplicationに実装application 。実装は、親フラグメント、このフラグメントが配置されているアクティビティ、およびapplication順序で検索されapplication


AndroidInjection.inject()は、スーパーメソッドを呼び出す前に、特定のメソッドで呼び出す必要があります。



Dagger-androidには使用できるクラスがあります(これらのクラスは既に必要なインターフェイスを実装し、 AndroidInjection.inject()メソッドを呼び出しています):



短剣アンドロイドサポート



何らかの理由でこれらのクラスのいずれかを拡張できない場合、必要なインターフェイスをいつでも実装できます。


短剣クラスの使用例:


メインコンポーネントを定義します。
コンポーネントがAndroidInjector継承する必要があるのは、 DaggerApplicationを使用する場合、 AndroidInjectorが返すメソッドを1つ実装する必要があります。 これは、 applicationに対してのみ行う必要がありapplication 。 メインコンポーネントを手動で識別します。


 @Component(modules = {AppModule.class, AndroidSupportInjectionModule.class}) @Singleton public interface AppComponent extends AndroidInjector<App> { @Component.Builder abstract class Builder extends AndroidInjector.Builder<App> {} } 

メインモジュールを定義する


このモジュールでは、アクティビティ、サービス、およびブロードキャストレシーバーの「マッピング」を追加します。 サブコンポーネントがそれらに対して生成され、メインコンポーネントに追加されます。 このモジュールをメインコンポーネントに接続しました。


 @Module abstract public class AppModule { @Provides @Singleton public static Context context(App app) { return app.getApplicationContext(); } @Provides @Singleton public static UserRepository userRepository(Context context) { return new UserRepositoryImpl(context); } @ContributesAndroidInjector(modules = { ActivityModule.class }) @ActivityScope abstract MainActivity mainActivity(); @ContributesAndroidInjector(modules = { ServiceModule.class }) @ServiceScope abstract MyIntentService myIntentService(); @ContributesAndroidInjector @ReceiverScope abstract SomeReceiver connectionReceiver(); } 

アプリケーションクラスを定義する


 public class App extends DaggerApplication { @Override protected AndroidInjector<? extends DaggerApplication> applicationInjector() { return DaggerAppComponent.builder().create(this); } } 

活動例


 public class MainActivity extends DaggerAppCompatActivity { @Inject UserRepository userRepository; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //userRepository    } } 

IntentServiceを使用した例


 public class MyIntentService extends DaggerIntentService { @Inject UserRepository userRepository; public MyIntentService() { super("MyIntentService"); } @Override protected void onHandleIntent(@Nullable Intent intent) { //userRepository    } } 

受信機の例


 public class SomeReceiver extends DaggerBroadcastReceiver { @Inject UserRepository userRepository; @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); //userRepository    } } 

コンポーネントのライフサイクル


dagger-androidを使用する場合、コンポーネントとサブコンポーネントは、作成されたAndroidコンポーネント( Activity, Fragment, Serviceなど)の存続期間中存続し、手動で破棄する必要はありません。 たとえば、アクティビティサブコンポーネントはAndroidInjection.inject()呼び出し時に作成され、アクティビティが破棄されるまで存続します。


動的パラメータ


dagger-androidを使用すると、サブコンポーネントをビルドする必要がなくなり、 AndroidInjection.inject() 1回の呼び出しで依存関係の要求が達成されます。 疑問が生じるかもしれません。どうすればこのようなことができますか:


 long userId = getArguments().getLong(USER_ID); getAppComponent() .plusUserComponent(new UserModule(userId)) .inject(this); 

userIdは、モジュールの動的パラメーターです。 たとえば、このパラメーターを使用してUserPresenter(UserRepository userRepository, Long userId)を作成できます。


実装オプション:


オプション1:
使用されるオブジェクトにパラメーターを設定します。


 public class UserPresenter { private UserView userView; private UserRepository userRepository; private long userId; @Inject public UserPresenter(UserView userView, UserRepository userRepository) { this.userView = userView; this.userRepository = userRepository; } public void setUserId(long userId) { this.userId = userId; } } public class UserFragment extends BaseFragment implements UserView { @Inject UserPresenter userPresenter; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); userId = getArguments().getLong(USER_ID); userPresenter.setUserId(userId); } } 

このオプションは、不変クラスには適していません。


オプション2:


作成時に動的パラメーターを受け入れないようにクラス自体を再構築し、メソッドを通じてパラメーター自体を使用します。


 public final class UserPresenter { private final UserView userView; private final UserRepository userRepository; @Inject public UserPresenter(final UserView userView, final UserRepository userRepository) { this.userView = userView; this.userRepository = userRepository; } public void loadUserInfo(long userId) { // } } public class UserFragment extends BaseFragment implements UserView { @Inject UserPresenter userPresenter; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); userId = getArguments().getLong(USER_ID); userPresenter.loadUserInfo(userId); } } 

オプション3:


ファクトリーを使用して、動的パラメーターを持つオブジェクトの作成を実装します。


 public final class UserPresenter { private final UserView userView; private final UserRepository userRepository; private final long userId; public UserPresenter(final UserView userView, final UserRepository userRepository, long userId) { this.userView = userView; this.userRepository = userRepository; this.userId = userId; } } public final class UserPresenterFactory { private final UserView userView; private final UserRepository userRepository; @Inject public UserPresenterFactory(UserView userView, UserRepository userRepository) { this.userView = userView; this.userRepository = userRepository; } public UserPresenter create(long userId) { return new UserPresenter(userView, userRepository, userId); } } public class UserFragment extends BaseFragment implements UserView { @Inject UserPresenterFactory userPresenterFactory; UserPresenter userPresenter; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); userId = getArguments().getLong(USER_ID); userPresenter = userPresenterFactory.create(userId); } } 

このようなファクトリーの作成は便利ではないか、時間がかかります。この問題を解決するには、 AutoFactoryを参照してください


RxJavaを使用する人により適したFernando Cejasのソリューションもあります。
ユースケースの動的パラメーター


おわりに


Dagger-androidを使用すると、Androidの基本コンポーネント( activity, fragment, serviceなど)の依存関係をより便利な方法で提供でき、サブコンポーネントを作成して制御する必要がなくなります。 アクティビティ、フラグメント、サービスなど より「きれい」に見えます。


この記事がdagger-androidの機能の理解に役立つことを願っています。



Source: https://habr.com/ru/post/J336462/


All Articles