ダガー2.11とAndroid

この記事では、Android向けの特殊なDagger 2モジュールの使用について説明し、Dagger 2の基本的な知識があることを示しています。


Dagger 2.10は、Android専用の新しいモジュールを導入しました。 このモジュールは、追加のライブラリとコンパイラで構成されるアドオンとして提供されます。
バージョン2.11では、いくつかの小さな変更、特に一部のクラスの名前が変更されたため、このバージョンが使用されます。


基礎理論


例で使用されるDagger 2の機能のいくつかを検討してください。


静的@Providesメソッド


静的な@Providesメソッドを作成できるようになりました。


 @Module public class RepositoryModule { @Provides public static NewsRepository newsRepository(SQLiteDatabase db) { return new NewsRepositoryImpl(db); } } 

静的な@Providesメソッドと通常のメソッドの主な違いは、モジュールインスタンスではなく、コンポーネントによって直接プルされることです。 静的な@Providesメソッドは、抽象モジュールクラスと通常のモジュールクラスの両方で使用できます。 静的メソッドは、スコープとスコープ解除の両方が可能です。


@Binds


Dagger 2では、 @Providesメソッドがなくても依存関係を提供できます。 これは、作成する必要のあるクラスのコンストラクターに@Injectを配置することで実現されます。


例を考えてみましょう:


 public class NewsRepositoryImpl implements NewsRepository { private SQLiteDatabase database; @Inject public NewsRepositoryImpl(SQLiteDatabase database) { this.database = database; } //.. } ... public class MyActivty extends BaseActivity { @Inject NewsRepositoryImpl newsRepo; @Override protected void onCreate(Bundle savedInstanceState) { getAppComponent.inject(this); } } 

このアプローチでは、具象クラスを型として記述できますが、NewsRepositoryインターフェイスへの依存関係を要求することはできません。 Dagger 2は、このインターフェイスに適切な実装を見つけることができません。


この制限を@Bindsするには、実装をインターフェイスにバインド(バインド)するために@Bindsが必要@Binds


@Binds機能:



例:


 @Module public abstract class RepositoryModule { @Binds @Singleton public abstract NewsRepository newsRepository(NewsRepositoryImpl repo); } 

これで、次を安全に記述できます。


 public class MyActivty extends BaseActivity { @Inject NewsRepository newsRepo; ... 

抽象クラスとして表されるモジュールには、次の機能があります。



コンストラクターで@Binds + @Injectを使用する場合、 @Binds + @Inject @Providesメソッドを完全に記述して実装する必要はありません。


モジュールにバインディングメソッド( @Binds )のみがある場合、このモジュールをインターフェイスとして作成するのが理にかなっています。


 @Module public interface AppModule { @Binds @Singleton NewsRepository newsRepository(NewsRepositoryImpl newsRepository); } 

ダガーAndroid


Dagger 2を使用した典型的なAndroidアプリケーションは次のようになります。


 public class SomeActivity { @Inject Api api; @Override protected void onCreate(Bundle savedInstanceState) { DaggerAppComponent .builder() .app(getApplication()) .build() .inject(this); } } 

さまざまなスコープ(アクティビティスコープ、フラグメントスコープなど)のサブコンポーネントが存在する場合もあります。


ここから、次の問題が発生します。



アンドロイド用の新しいモジュールはこの問題を解決します。


依存関係の接続


 //Dagger 2 compile 'com.google.dagger:dagger:2.11' annotationProcessor 'com.google.dagger:dagger-compiler:2.11' //Dagger-Android compile 'com.google.dagger:dagger-android:2.11' annotationProcessor 'com.google.dagger:dagger-android-processor:2.11' //    support  compile 'com.google.dagger:dagger-android-support:2.11' 

Androidのみに関連する依存関係を接続することはできません。 彼らはサプリメントとして来ます。


実装


ご存じのとおり、 @Scopeアノテーションとその子孫は、モジュール内のメソッド、および必要な依存関係を提供するコンポーネント/サブコンポーネントをマークします。
@Scopeは、作成された(表現された)オブジェクトの有効期間を決定し、それによって効果的なメモリ管理を表します。


スコープのアプリケーションの構造の例を考えてみましょう。



この例では、FacadeはUseCase / Interactorの類似物です。 このアプリケーションは、新しいDagger 2モジュールを使用してこれをどのように適用できるかを示す3つのミサゴで構成される構造を持ち、 @ContributesAndroidInjectorアノテーションのみを使用するオプションもここで検討されます。


実装を取得する:


1.メインモジュールを定義します。


 @Module(includes = {AndroidSupportInjectionModule.class}) public interface AppModule { @Singleton @Binds Repository repository(RepositoryImpl repository); @ActivityScope @ContributesAndroidInjector(modules = {MainActivityModule.class}) MainActivity mainActivityInjector(); } 

このモジュールには以下が追加されました。



2. MainActivityModule


 @Module public interface MainActivityModule { @ActivityScope @Binds Facade facade(FacadeImpl facade); @ActivityScope @Binds MainRouter router(MainRouterImpl mainRouter); } 

AndroidInectorを使用すると、次のようにAndroidInectorインスタンスを使用できます。 このアクティビティはグラフの一部ですが、これはAndroidInjection.inject(this)を呼び出してアクティビティインスタンスを渡すために発生します(以下を参照)。


アクティビティのインスタンスを依存関係として取得する例


 public class MainRouterImpl extends BaseRouterImpl<MainActivity> implements MainRouter { @Inject public MainRouterImpl(MainActivity activity) { super(activity); } @Override public void showSomeScreen() { replaceFragment(R.id.content, new MyFragment()); } } 

3.ルートモジュールを作成します。ルートコンポーネントには、AppModuleとApplicationの唯一のインジェクションが含まれます。


 @Singleton @Component(modules = { AppModule.class }) public interface AppComponent { @Component.Builder interface Builder { @BindsInstance Builder context(Context context); AppComponent build(); } void inject(App app); } 

4.アプリケーションにHasActivityInjectorインターフェースを実装し、AndroidInectorディスパッチャーを注入する必要があります。


 public class App extends Application implements HasActivityInjector { @Inject DispatchingAndroidInjector<Activity> dispatchingAndroidInjector; @Override public void onCreate() { super.onCreate(); DaggerAppComponent .builder() .context(this) .build() .inject(this); } @Override public AndroidInjector<Activity> activityInjector() { return dispatchingAndroidInjector; } } 

特定のActivity AndroidInectorを見つけるには、 DispatchingAndroidInjector必要です。


5.これですべてを活用できます。


 public class MainActivity extends Activity { @Inject Repository repository; //Singleton scope @Inject Facade facade; //activity scope @Inject MainRouter router; //activity scope public void onCreate(Bundle savedInstanceState) { AndroidInjection.inject(this); //     super.onCreate(savedInstanceState); } } 

ここで見るように、コンポーネントとサブコンポーネントはありませんが、同時に異なるスコープで依存関係を取得する機会があります。 さらに、ルーターを作成するために、アクティビティインスタンス自体を(依存関係として)作成する必要があります。


AndroidInjection.inject(this)の構築は基本クラスにAndroidInjection.inject(this)でき、すべてが同じように機能します。


どのように機能しますか? AndroidInjection.inject(this)を呼び出すと、Dagger 2はHasActivityInjectorインターフェイスを実装するアプリケーションにアクセスし、 HasActivityInjectorを介して、アクティビティクラスによって目的のAndroidInector (アクティビティサブコンポーネント)を見つけ、目的のスコープで依存関係を初期化します。


6. @FragemntScopeの実装に@FragemntScopeましょう。


MainActivityModuleを更新する必要があります。


 @Module public interface MainActivityModule { @ActivityScope @Binds Facade facade(FacadeImpl facade); @ActivityScope @Binds MainRouter router(MainRouterImpl mainRouter); @FragmentScope @ContributesAndroidInjector(modules = {MyFragmentModule.class}) MyFragment myFragment(); } 

アクティベーションの場合と同様に、フラグメント用に同様のAndroidInjectコンストラクトを追加しました。
したがって、@FragmentScope @FragmentScope持つ特定のフラグメントに対してAndroidInject(サブコンポーネント)が生成され@FragmentScope 。 このモジュールで示されている依存関係@Singleton@ActivityScopeと、このフラグメントのモジュールとして示されている依存関係は、利用可能になります。


7. HasSupportFragmentInjectorインターフェイスの基本アクティビティと実装を追加します。


 abstract public class BaseActivity extends AppCompatActivity implements HasSupportFragmentInjector { @Inject DispatchingAndroidInjector<Fragment> fragmentInjector; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { AndroidInjection.inject(this); super.onCreate(savedInstanceState); } @Override public AndroidInjector<Fragment> supportFragmentInjector() { return fragmentInjector; } } 

Applicationと同様に、 AndroidInjectorAndroidInjectorディスパッチャになり、 AndroidInjector (サブコンポーネント)に必要なフラグメントが提供されます。


8. MyFragmentModule


 @Module public interface MyFragmentModule { @Binds MyView myView(MyFragment myFragment); } 

アクティビティの場合と同じように、 AndroidInjectionを使用します(サポートライブラリを使用する場合はAndroidSupportInjection )。フラグメントインスタンスを使用できます。 これはグラフの一部であり、依存関係として渡すことができます。また、インターフェイスにバインドすることもできます。


プレゼンターの例:


 public class MyPresenter { private MyView view; //  , ..     private Facade facade; //@ActivityScope private MainRouter router; //@ActivityScope @Inject public MyPresenter(MyView view, Facade facade, MainRouter router) { this.view = view; this.facade = facade; this.router = router; } //... } 

9.フラグメント内の注入


 public class MyFragment extends Fragment implements MyView { @Inject MyPresenter presenter; //@FragmentScope @Override public void onAttach(Context context) { AndroidSupportInjection.inject(this); super.onAttach(context); presenter.doSomething(); } @Override public void onResult(String result) { //Todo } } 

AndroidSupportInjectionコンストラクトは、基本クラスにレンダリングできます。


おわりに


私の意見では、新しいandroid-daggerモジュールは、Androidにより適切な依存関係プロビジョニングを提供します。 インジェクションメソッドを基本クラスに取り込むことができ、スコープに応じてより便利な分離を取得できます。サブコンポーネントをスローする必要はありません。また、プレゼンターグラフなどの外部依存関係として使用できるアクセシビリティオブジェクトとフラグメントオブジェクトがあります。


GitHubの
パート2



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


All Articles