web-dev-qa-db-ja.com

Dagger 2.10 Androidサブコンポーネントとビルダー

新しい(2.10の)dagger.Androidクラスを使用して、他のモジュールに依存するサブコンポーネントを使用して物を注入しようとしているため、それらのモジュールのセッターを備えたビルダーがあります。 https://google.github.io/dagger/Android.html のドキュメントではこれについて説明していますが、これらのセッターを実際に作成および/または呼び出す方法については明確ではありません。

上記のリンクからの引用:

AndroidInjection.inject()は、アプリケーションからDispatchingAndroidInjectorを取得し、アクティビティをinject(Activity)に渡します。 DispatchingAndroidInjectorは、AndroidInjector.Factoryでアクティビティのクラス(YourActivitySubcomponent.Builder)を検索し、AndroidInjector(YourActivitySubcomponent)を作成して、アクティビティをinject(YourActivity)に渡します。

Builderのセッターを呼び出すことができるようにするには、どこかにアクセスして、Builderに必要なすべてのデータがあることを確認する必要があるように思われます。私が見ている問題は、実行時に、サブコンポーネント用に生成されたビルダーがAndroidInjectorによって呼び出されると、IllegalStateException: MODULE must be setを取得することです。

問題のサブコンポーネントは、実際にはアクティビティではなくフラグメント用ですが、それが重要かどうかはわかりません。これを行う方法についてのアイデアはありますか?

17
Petter Måhlén

つまり、必要な他のモジュールを提供するために、Builder(インターフェイスではなく抽象クラス)で seedInstanceへの呼び出しをオーバーライドする することになっています。

edit:実行する前に、そのモジュールに本当に合格する必要があることを確認してください。 Damonは別の回答で追加されました のように、Androidクラス用に特定のモジュールを作成している場合は、そのクラスの自動インジェクションを利用して、モジュールからコンストラクターパラメーターを削除する方が簡単な場合は、構成またはインスタンスをグラフから外します。これにより、不要なインスタンスや仮想メソッドの呼び出しが回避されるため、パフォーマンスが向上する可能性があります。


まず、dagger.Androidを30秒で:各アクティビティまたはフラグメントにその親を認識させるのではなく、アクティビティ(またはフラグメント)はAndroidInjection.inject(this)、アプリケーションのHasActivityInjector(または親フラグメント、アクティビティ、およびアプリケーションのHasFragmentInjector)をチェックします。アイデアは、マルチバインディングによって作成された_Map<Class, AndroidInjector.Factory>_にバインディングを提供することです。ここで、提供されたバインディングは、ほぼ常に、オブジェクト固有のサブコンポーネントをビルドするサブコンポーネントビルダーです。

AndroidInjection.inject(this)AndroidInjector.Factory.create(T instance)からわかるように、アクティビティ固有またはフラグメント固有の詳細をBuilderに渡す機会はあまりありません。代わりに、サブコンポーネントビルダーがseedInstance実装をオーバーライドするという考え方です。 seedInstanceのドキュメントのように:

構築されたinstanceのバインディンググラフで使用されるAndroidInjectorを提供します。デフォルトでは、これはBindsInstanceメソッドとして使用されますが、アクティビティへの参照を必要とするモジュールを提供するためにオーバーライドされる場合があります。

これは、inject(Object)に渡されるのと同じインスタンスである必要があります。

これは次のようになります。

_@Subcomponent(modules = {OneModule.class, TwoModule.class})
public interface YourActivitySubcomponent extends AndroidInjector<YourActivity> {

  // inject(YourActivity) is inherited from AndroidInjector<YourActivity>

  @Builder
  public abstract class Builder extends AndroidInjector.Builder<YourActivity> {
    // Here are your required module builders:
    abstract Builder oneModule(OneModule module);
    abstract Builder twoModule(TwoModule module);

    // By overriding seedInstance, you don't let Dagger provide its
    // normal @BindsInstance implementation, but you can supply the
    // instance to modules or call your own BindsInstance:
    @Override public void seedInstance(YourActivity activity) {
      oneModule(new OneModule(activity));
      twoModule(new TwoModule(activity.getTwoModuleParameter()));
    }
  }
}
_

ここでの前提は、モジュールのactivityインスタンスを待つ必要があるということです。そうでない場合は、サブコンポーネントをバインドするときにそれらを呼び出すオプションもあります。

_@Provides @IntoMap @ActivityKey(YourActivity.class)
AndroidInjector.Factory bindInjector(YourActivitySubcomponent.Builder builder) {
  return builder
      .oneModule(new OneModule(...))
      .twoModule(new TwoModule(...));
}
_

...しかし、それができれば、それらのモジュールをオーバーライドし、モジュールのコンストラクターパラメーターを提供できるゼロ引数コンストラクターを実装し、Daggerにそれらを作成させることで、これらのバインディングをより簡単に処理できます。パブリックゼロ引数コンストラクターを備えたモジュール。

それは機能しますが、それは不要です。 seedInstanceメソッドはアクティビティインスタンスをグラフに提供するため、状態のないMyActivityModuleを作成し、@ ProvidesメソッドでMyActivityをリクエストするだけです。

class MyActivityModule {
  @Provides
  static SomethingDerivedFromMyActivity providesMethod(MyActivity myActivity) {
    return myActivity.somethingDerived();
  }
}

これを行うと、モジュールインスタンスが保存され、生成されたファクトリをよりスリムにすることができます。

https://github.com/google/dagger/issues/615 から。

3
Damon Yuan