26

私はおそらく何かを見逃していましたが、 @Singleton のようなスコープは「スコープ付きライフサイクル」を定義するために使用されると思いました。

AndroidアプリでDagger 2を使用しています(ただし、問題は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();

}

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

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

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

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

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

4

2 に答える 2

53

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

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

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

または、対象外のままにしておくこともできます。

スコープに関しては、最初のDagger 2 提案からの概要を次に示します。

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

その宣言により、短剣は次の制約を適用できます。

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

このルールの組み合わせの目的は、スコープが適用されたときに、コンポーネントが Dagger 1.0 plus() の ObjectGraph で使用していたのと同じ構造で構成されることを強制することですが、すべてのオブジェクト グラフの静的な知識を持つ機能を備えています。バインディングとそのスコープ。別の言い方をすれば、スコープが適用されると、これにより、構築できるグラフが正しく構築できるものだけに制限されます。

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

お役に立てば幸いです:)。すぐに理解するのはかなり難しく、時間がかかります。少なくとも私にとってはそうでした。

于 2015-04-14T05:13:39.830 に答える