web-dev-qa-db-ja.com

Dagger 2のスコープ

たぶん何かを見逃したかもしれませんが、@ Singletonのようなスコープは「スコープ付きライフサイクル」の定義に使用されると思いました。

私はDagger 2をAndroidアプリで使用しています(ただし、問題はAndroidに関連しているとは思いません)。

私は1つのモジュールを持っています:

@Module public class MailModule {

  @Singleton @Provides public AccountManager providesAccountManager() {
    return new AccountManager();
  }

  @Singleton @Provides public MailProvider providesMailProvider(AccountManager accountManager) {
    return new MailProvider(accountManager);
  }
}

@Singletonスコープを持つ2つの異なるコンポーネントがあります。

@Singleton
@Component(modules = MailModule.class)
public interface LoginComponent {

  public LoginPresenter presenter();
}


@Singleton
@Component(
    modules = MailModule.class
)
public interface MenuComponent {

  MenuPresenter presenter();

}

MenuPresenterLoginPresenterの両方に、@Injectコンストラクターがあります。 MenuPresenterはMailProviderをパラメーターとして期待しますが、LoginPresenterはAccountManagerを取ります。

  @Inject public MenuPresenter(MailProvider mailProvider) { ... }

  @Inject public LoginPresenter(AccountManager accountManager) { ... }

ただし、コンポーネントを使用してMenuPresenterまたはLoginPresenterを作成するたびに、MailProviderおよびAccountManagerの新しいインスタンスが新しく作成されます。私はそれらが同じスコープ内にあると思ったので、(同じスコープ内の)シングルトンのようなものでなければなりません。

完全に間違っていることを理解しましたか。ダガー2の複数のコンポーネントに対して実際のシングルトンを定義するにはどうすればよいですか?

26
sockeqwe

LoginComponentMenuComponentが別々に使用されていると仮定します。 LoginActivityおよびMenuActivityで。各コンポーネントはActivity.onCreateに組み込まれています。その場合、コンポーネントは、結合するスコープに関係なく、新しいアクティビティ、モジュール、および依存関係も作成されるたびに再作成されます。したがって、毎回MainProviderAccountManagerの新しいインスタンスを取得します。

MenuActivityLoginActivityには別々のライブサイクルがあるため、MailModuleからの依存関係は両方でシングルトンになることはできません。必要なのは、@Singletonスコープ(たとえばApplicationサブクラス)でルートコンポーネントを宣言し、MenuComponentおよびLoginComponentをそれに依存させることです。アクティビティレベルのコンポーネントは@Singletonスコープにすることはできません。@Scopeアノテーションを使用して独自のスコープを作成することをお勧めします。例:

@Retention(RetentionPolicy.RUNTIME)
@Scope
public @interface MenuScope {
}

または、対象外のままにすることもできます。

スコープについては、最初から簡単に説明します Dagger 2提案

@Singleton
@Component(modules = {…})
public interface ApplicationComponent {}

この宣言により、短剣は以下の制約を実施できます。

  • 特定のコンポーネントには、スコープのないバインディングまたは宣言されたスコープのバインディング(クラスのスコープアノテーションを含む)のみを含めることができます。つまりコンポーネントは2つのスコープを表すことはできません。スコープがリストされていない場合、バインディングのスコープは解除されます。
  • スコープコンポーネントには、スコープ依存関係が1つしかありません。これは、2つのコンポーネントがそれぞれ独自のスコープバインディングを宣言しないことを強制するメカニズムです。例えば。それぞれ独自の@Singleton Cacheを持つ2つのシングルトンコンポーネントが破損します。
  • コンポーネントのスコープは、その推移的な依存関係のいずれにも現れてはなりません。例:SessionScoped-> RequestScoped-> SessionScopedは意味がなく、バグです。
  • @Singletonは、スコープ依存関係を持つことができないという点で特別に扱われます。誰もがシングルトンが「ルート」であることを期待しています。

このルールの組み合わせの目的は、スコープが適用されたときに、コンポーネントがDagger 1.0 plus() 'd ObjectGraphsで使用していたのと同じ構造で構成されることを強制することですが、すべての静的な知識をバインディングとそのスコープ。別の言い方をすれば、スコープが適用されたとき、これは、構築できるグラフを、正しく構築できるグラフのみに制限します。

私自身の練習から、@Singletonをまったく使用しない方が明確です。その代わりに、@ApplicationScopeを使用します。アプリケーション全体でシングルトンを定義するのに役立ち、@Singletonのような追加の制限はありません。

それがあなたを助けることを願っています:)。少なくとも私にとっては、すぐに理解し、時間がかかるのは非常に難しいです。

50

以下を実行して、複数のコンポーネントの実際のシングルトンを定義できます。私は@ApplicationScopedおよび@ActivityScopedは異なるスコープになります。

@Module public class MailModule {
  @Provides @ApplicationScoped 
  public AccountManager providesAccountManager() {
    return new AccountManager();
  }

  @Provides @ApplicationScoped
  public MailProvider providesMailProvider(AccountManager accountManager) {
        return new MailProvider(accountManager);
  }
}

次に、MailComponentに対してMailModuleを定義できます。 LoginComponentMenuComponentは、MailComponentに依存できます。

@ApplicationScoped
@Component(modules = MailModule.class)
public interface MailComponent {
  MailProvider mailProvider();
  AccountManager accountManager();
}

@ActivityScoped
@Component(dependencies = MailComponent.class)
public interface LoginComponent {
  LoginPresenter presenter();
}

@ActivityScoped
@Component(dependencies = MailComponent.class)
public interface MenuComponent {
  MenuPresenter presenter();
}

MailComponentは、以下に示すように初期化でき、MenuComponentおよびLoginComponentで再び使用できます。

MailComponent mailComponent = DaggerMailComponent.builder().build();

DaggerMenuComponent.builder().mailComponent(mailComponent).build();

DaggerLoginComponent.builder().mailComponent(mailComponent).build()            
7
Praveer Gupta