たぶん何かを見逃したかもしれませんが、@ 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();
}
MenuPresenter
とLoginPresenter
の両方に、@Inject
コンストラクターがあります。 MenuPresenterはMailProvider
をパラメーターとして期待しますが、LoginPresenterはAccountManager
を取ります。
@Inject public MenuPresenter(MailProvider mailProvider) { ... }
@Inject public LoginPresenter(AccountManager accountManager) { ... }
ただし、コンポーネントを使用してMenuPresenter
またはLoginPresenter
を作成するたびに、MailProvider
およびAccountManager
の新しいインスタンスが新しく作成されます。私はそれらが同じスコープ内にあると思ったので、(同じスコープ内の)シングルトンのようなものでなければなりません。
完全に間違っていることを理解しましたか。ダガー2の複数のコンポーネントに対して実際のシングルトンを定義するにはどうすればよいですか?
LoginComponent
とMenuComponent
が別々に使用されていると仮定します。 LoginActivity
およびMenuActivity
で。各コンポーネントはActivity.onCreate
に組み込まれています。その場合、コンポーネントは、結合するスコープに関係なく、新しいアクティビティ、モジュール、および依存関係も作成されるたびに再作成されます。したがって、毎回MainProvider
とAccountManager
の新しいインスタンスを取得します。
MenuActivity
とLoginActivity
には別々のライブサイクルがあるため、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
のような追加の制限はありません。
それがあなたを助けることを願っています:)。少なくとも私にとっては、すぐに理解し、時間がかかるのは非常に難しいです。
以下を実行して、複数のコンポーネントの実際のシングルトンを定義できます。私は@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
を定義できます。 LoginComponent
とMenuComponent
は、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()