[解決済み] Dagger 2のコンポーネント(オブジェクトグラフ)のライフサイクルを決定するものは何ですか?
質問
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;
}
}
子スコープが存在するのは、それへの参照を保持している間だけで、この場合はActivityのライフサイクルのことです。onDestroyで参照を削除することで、スコープされたグラフがガベージコレクトされるのを確実にします。
EDIT
Jesse Wilsonは最近 誤字脱字
<ブロッククオートDagger 1.0はスコープ名をひどく間違えていました ... Singletonアノテーションはルートグラフとカスタムグラフの両方に使用されるので、実際のスコープが何であるかを把握するのは厄介です。
と、私が読んだり聞いたりしたすべてのことは、Dagger 2がスコープの動作方法を改善することを指していますが、その違いを理解するのに苦労しています。下の @Kirill Boyarshinov のコメントによると、コンポーネントまたは依存関係のライフサイクルは、これまでどおり、具体的な参照によって決定されるとのことです。つまり、Dagger 1.x と 2.0 のスコープの違いは、純粋に意味上の明確さの問題なのでしょうか?
私の理解
ダガー1.x
依存関係は
@Singleton
であるか、そうでないかです。これはルートグラフとサブグラフの依存関係にも同様に当てはまり、依存関係がどのグラフに束縛されているのかが曖昧になる原因となっていました(
Daggerでは、サブグラフ内のシングルトンはキャッシュされるのですか?
)
Dagger 2.0
カスタムスコープを使用すると、意味的に明確なスコープを作成できますが、機能的には
@Singleton
を適用するのと機能的には同じです。
// 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
はアプリケーションレベルのシングルトンインスタンスを対象としており、カスタムスコープはライフサイクルが短いシングルトン依存関係をアノテートするための好ましい方法です。
開発者は、不要になった参照を削除してコンポーネント/依存関係のライフサイクルを管理し、コンポーネントが意図したスコープで一度だけ作成されることを保証する責任がありますが、カスタムスコープアノテーションによってそのスコープを特定しやすくなります。
6400 万ドルの質問*」。
Dagger 2のスコープとライフサイクルに関する私の理解は正しいですか?
* 実際には64'000ドルの質問ではありません。
どのように解決するのですか?
ご質問の件ですが
Dagger 2のコンポーネント(オブジェクトグラフ)のライフサイクルは何で決まるのでしょうか?
短い答えは あなたが決めることです。 . コンポーネントは以下のようにスコープを与えることができます。
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ApplicationScope {
}
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}
これらは、2つの点で役に立ちます。
- スコープの検証: コンポーネントは、スコープされていないプロバイダ、またはコンポーネントと同じスコープのプロバイダしか持つことができません。
.
@Component(modules={ApplicationModule.class})
@ApplicationScope
public interface ApplicationComponent {
Something something();
AnotherThing anotherThing();
void inject(Whatever whatever);
}
@Module
public class ApplicationModule {
@ApplicationScope //application-scoped provider, only one can exist per component
@Provides
public Something something() {
return new Something();
}
@Provides //unscoped, each INJECT call creates a new instance
public AnotherThing anotherThing() {
return new AnotherThing();
}
}
- スコープされた依存関係をサブスコープすることを可能にします。したがって、"superscoped" コンポーネントから提供されたインスタンスを使用する "subscoped" コンポーネントを作成することを可能にします。
これは
@Subcomponent
アノテーション、またはコンポーネントの依存関係で行うことができます。私は個人的に依存関係を好む。
@Component(modules={ApplicationModule.class})
@ApplicationScope
public interface ApplicationComponent {
Something something();
AnotherThing anotherThing();
void inject(Whatever whatever);
ActivityComponent newActivityComponent(ActivityModule activityModule); //subcomponent factory method
}
@Subcomponent(modules={ActivityModule.class})
@ActivityScope
public interface ActivityComponent {
ThirdThingy thirdThingy();
void inject(SomeActivity someActivity);
}
@Module
public class ActivityModule {
private Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
//...
}
ApplicationComponent applicationComponent = DaggerApplicationComponent.create();
ActivityComponent activityComponent = applicationComponent.newActivityComponent(new ActivityModule(SomeActivity.this));
または、以下のようにコンポーネントの依存関係を使用することもできます。
@Component(modules={ApplicationModule.class})
@ApplicationScope
public class ApplicationComponent {
Something something();
AnotherThing anotherThing();
void inject(Whatever whatever);
}
@Component(dependencies={ApplicationComponent.class}, modules={ActivityModule.class})
@ActivityScope
public interface ActivityComponent extends ApplicationComponent {
ThirdThingy thirdThingy();
void inject(SomeActivity someActivity);
}
@Module
public class ActivityModule {
private Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
//...
}
ApplicationComponent applicationComponent = DaggerApplicationComponent.create();
ActivityComponent activityComponent = DaggerActivityComponent.builder().activityModule(new ActivityModule(SomeActivity.this)).build();
大切なこと
-
スコープ付きプロバイダは、与えられたスコープに対して1つのインスタンスを作成します。 各コンポーネントに対して . つまり、コンポーネントは自分自身のインスタンスを追跡しますが、他のコンポーネントは共有スコーププールや何らかの魔法を持っていないことを意味します。あるスコープで1つのインスタンスを持つには、そのコンポーネントのインスタンスが1つ必要です。 そのために
ApplicationComponent
を使用して、自身のスコープされた依存関係にアクセスすることができます。 -
コンポーネントは、1つのスコープされたコンポーネントのみをサブスコープすることができます。複数のスコープされたコンポーネントの依存関係は認められません。
関連
-
エラー java.util.NoSuchElementException
-
スキャナは、タイプに解決することはできません最もルーキー初心者の質問
-
プロジェクトの依存関係を解決できなかった 解決
-
spring aop アドバイスからの Null 戻り値が、サマリーのプリミティブ戻り値と一致しない。
-
javaでクラスを作成すると、enclosing classでないように見える
-
HttpClientがGZIP形式でない場合の対処法
-
あるコードに出会いましたが、何に使うのか理解できません。 List<String> list = new ArrayList<String>() { { a
-
maven プラグイン エラー プラグインの実行は、ライフサイクル構成ソリューションの対象外です。
-
[解決済み] JavaにおけるHashMapとHashtableの違いは何ですか?
-
[解決済み] Javaにおけるpublic、protected、package-private、privateの違いは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
springboot project MIMEタイプ text/htmlで転送された静的ファイルを読み込む。
-
この行に複数のマーカーがある - HttpServletResponseが型エラーに解決できない
-
this()の呼び出しはコンストラクタ本体の最初の文でなければならない 例外解決と原因分析
-
Eclipseでプロジェクトエクスプローラービューとパッケージエクスプローラービューを使う
-
スレッド "main" で例外発生 java.lang.ArrayIndexOutOfBoundsException: 4 at text.Division.main(Divisi
-
リソースの読み込みに失敗しました。サーバーはステータス500(内部サーバーエラー)で応答しました。
-
javaでよく使われる英単語
-
Eclipse起動エラー:javaは起動したが、終了コード=1を返した(ネット上の様々な落とし穴)
-
Error: java.lang.NoClassDefFoundError: クラス XXXX を初期化できませんでした
-
SocketTimeoutExceptionの解決方法です。読み込みがタイムアウトした