私はDagger 2のスコープ、特にスコープ付きグラフのライフサイクルに頭を抱えようとしています。スコープを離れたときにクリーンアップされるコンポーネントをどのように作成しますか。
Androidアプリケーションの場合、Dagger 1.xを使用すると、通常、アクティビティレベルで子スコープを作成するために拡張するアプリケーションレベルにルートスコープがあります。
public class MyActivity {
private ObjectGraph mGraph;
public void onCreate() {
mGraph = ((MyApp) getApplicationContext())
.getObjectGraph()
.plus(new ActivityModule())
.inject(this);
}
public void onDestroy() {
mGraph = null;
}
}
子スコープへの参照を保持している限り、子スコープは存在しました。この場合は、アクティビティのライフサイクルでした。onDestroyで参照を削除することで、スコープ付きグラフがガベージコレクションされるのを自由にできるようになりました。
編集
ジェシー・ウィルソンは最近メジャーカルパを投稿しました
Dagger 1.0はスコープ名をひどく台無しにしています... @Singletonアノテーションはルートグラフとカスタムグラフの両方に使用されているため、実際のスコープが何かを理解するのは難しいです。
そして、私が読んだり聞いたりしたすべてのことは、スコープの動作を改善するDagger 2に向けられていますが、その違いを理解するのに苦労しています。以下の@Kirill Boyarshinovのコメントによると、コンポーネントまたは依存関係のライフサイクルは、通常どおり、具体的な参照によって決定されます。では、Dagger 1.xスコープと2.0スコープの違いは、純粋に意味の明確さの問題ですか?
私の理解
ダガー1.x
依存関係はどちら@Singleton
かでした。これは、ルートグラフとサブグラフの依存関係にも同様に当てはまり、依存関係がどのグラフにバインドされているかが曖昧になります(「ダガー内」は、キャッシュされたサブグラフ内のシングルトンであるか、新しいアクティビティサブグラフのときに常に再作成されますか?構築されていますか?)
ダガー2.0
カスタムスコープを使用すると、意味的に明確なスコープを作成できますが、機能的に@Singleton
はDagger 1.xでの適用と同等です。
// Application level
@Singleton
@Component( modules = MyAppModule.class )
public interface MyAppComponent {
void inject(Application app);
}
@Module
public class MyAppModule {
@Singleton @Named("SingletonScope") @Provides
StringBuilder provideStringBuilderSingletonScope() {
return new StringBuilder("App");
}
}
// Our custom scope
@Scope public @interface PerActivity {}
// Activity level
@PerActivty
@Component(
dependencies = MyAppComponent.class,
modules = MyActivityModule.class
)
public interface MyActivityComponent {
void inject(Activity activity);
}
@Module
public class MyActivityModule {
@PerActivity @Named("ActivityScope") @Provides
StringBuilder provideStringBuilderActivityScope() {
return new StringBuilder("Activity");
}
@Name("Unscoped") @Provides
StringBuilder provideStringBuilderUnscoped() {
return new StringBuilder("Unscoped");
}
}
// Finally, a sample Activity which gets injected
public class MyActivity {
private MyActivityComponent component;
@Inject @Named("AppScope")
StringBuilder appScope
@Inject @Named("ActivityScope")
StringBuilder activityScope1
@Inject @Named("ActivityScope")
StringBuilder activityScope2
@Inject @Named("Unscoped")
StringBuilder unscoped1
@Inject @Named("Unscoped")
StringBuilder unscoped2
public void onCreate() {
component = Dagger_MyActivityComponent.builder()
.myApplicationComponent(App.getComponent())
.build()
.inject(this);
appScope.append(" > Activity")
appScope.build() // output matches "App (> Activity)+"
activityScope1.append("123")
activityScope1.build() // output: "Activity123"
activityScope2.append("456")
activityScope1.build() // output: "Activity123456"
unscoped1.append("123")
unscoped1.build() // output: "Unscoped123"
unscoped2.append("456")
unscoped2.build() // output: "Unscoped456"
}
public void onDestroy() {
component = null;
}
}
使用@PerActivity
すると、このコンポーネントのライフサイクルに関する意図が伝達されますが、最終的にはコンポーネントをいつでもどこでも使用できます。Daggerの唯一の約束は、特定のコンポーネントについて、スコープの注釈が付けられたメソッドが単一のインスタンスを返すことです。また、Dagger 2はコンポーネントのスコープアノテーションを使用して、モジュールが同じスコープ内またはスコープ外の依存関係のみを提供することを確認することも想定しています。
要約すれば
依存関係は依然としてシングルトンまたは非シングルトンのいずれか@Singleton
ですが、現在はアプリケーションレベルのシングルトンインスタンスを対象としており、カスタムスコープはシングルトンの依存関係に短いライフサイクルでアノテーションを付けるための推奨される方法です。
開発者は、不要になった参照を削除することでコンポーネント/依存関係のライフサイクルを管理し、コンポーネントが意図されたスコープ内で1回だけ作成されるようにしますが、カスタムスコープアノテーションにより、スコープを簡単に識別できます。 。
64,000ドルの質問*
Dagger 2のスコープとライフサイクルに関する私の理解は正しいですか?
*実際には$ 64'000の質問ではありません。
plus()
新しいグラフへの参照を使用してアプリケーションレベルのObjectGraphオブジェクトをサブグラフ化すると、アクティビティに格納され、そのライフサイクルにバインドされました(で逆参照onDestroy
)。スコープに関しては、コンポーネントの実装がコンパイル時にエラーなしで生成され、すべての依存関係が満たされていることを保証します。したがって、それは文書化の目的だけではありません。このスレッドからいくつかの例を確認してください。