web-dev-qa-db-ja.com

各フラグメント(またはアクティビティなど)のダガー2カスタムスコープ

Dagger 2でカスタムスコーピングを行う2つの異なる方法を提案しているように見える2つの異なる記事を見てきました。

  1. MVPプレゼンターは構成変更パート2を生き残りますGithubリポジトリ ):

    • 各フラグメントに一意のカスタムスコープを使用します。 @Hello1Scopeおよび@Hello2Scope にとって Hello1FragmentおよびHello2Fragmentそれぞれ
  2. Androidのテイスティングダガー2

    • すべてのフラグメントに単一のカスタムスコープを使用します。 @PerFragment

私が理解していることから、方法2のように、すべてのフラグメントに使用できる単一のスコープを定義しても大丈夫なはずです(つまり、@PerFragment)。実際(私が間違っている場合は修正してください)、カスタムスコープの名前は無関係であり、重要なのはサブコンポーネント(つまり、アプリケーション、アクティビティ、またはフラグメント)が作成された場所だけです。

ケース1のように、各フラグメントに一意のスコープを定義するユースケースはありますか?

35
bcorso

@vaughandroidによる回答を読んだ後、 Dagger 2のコンポーネント(オブジェクトグラフ)のライフサイクルを決定するものは何ですか? カスタムスコープは自分の質問に答えるのに十分理解できていると思います。

まず、dagger2のコンポーネント、モジュール、およびスコープアノテーションを処理する際のいくつかのルールを次に示します。

  • コンポーネントmustには、(単一の)スコープアノテーションがあります(例:@Singletonまたは@CustomScope)。
  • モジュールにはスコープ注釈がありません
  • モジュールメソッドは、そのコンポーネントまたはスコープなしに一致する(単一)スコープを持つことができます。ここで、
    • Scoped:コンポーネントのインスタンスごとに1つのインスタンスが作成されることを意味します。
    • nscoped:それぞれのinject()またはプロバイダーの呼び出しで新しいインスタンスが作成されることを意味します
    • 注: Dagger2は、@Singletonをルートコンポーネント(およびそのモジュール)専用に予約します。サブコンポーネントはカスタムスコープを使用する必要がありますが、そのスコープの機能は@Singletonとまったく同じです。

ここで、質問に答えるために、概念的に異なるスコープごとに新しい名前付きスコープを作成します。たとえば、コンポーネントをインスタンス化する場所を示す@PerActivity@PerFragment、または@PerView注釈を作成して、その有効期間を示します。

:これは2つの極端な妥協案です。ルートコンポーネントと、必要なnサブコンポーネントの場合を考えます。

  • 少なくとも 2つの注釈(@Singletonおよび@SubSingleton)、および
  • atmostn + 1注釈(@Singleton@SubSingleton1、... @SubSingletonN)。

例:

アプリケーション:

/** AppComponent.Java **/ 
@Singleton
@Component( modules = AppModule.class )
public interface AppComponent{
    void inject(MainActivity mainActivity);
}

/** AppModule.Java **/
@Module
public class AppModule{
    private App app;

    public AppModule(App app){
        this.app = app;
    }

    // For singleton objects, annotate with same scope as component, i.e. @Singleton
    @Provides @Singleton public App provideApp() { return app; }
    @Provides @Singleton public EventBus provideBus() { return EventBus.getDefault(); }
}

フラグメント:

/** Fragment1Component.Java **/
@PerFragment
@Component( modules = {Fragment1Module.class}, dependencies = {AppComponent.class} )
public interface Fragment1Component {
    void inject(Fragment1 fragment1);
}

/** Fragment1Module.Java **/ 
@Module
public class Fragment1Module {
    // For singleton objects, annotate with same scope as component, i.e. @PerFragment
    @Provides @PerFragment public Fragment1Presenter providePresenter(){
        return new Fragment1Presenter();
    }
}

/** PerFragment.Java **/ 
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface PerFragment {}
79
bcorso

あなたの理解は正しいです。名前付きスコープを使用すると、意図を伝えることができますが、すべて同じように機能します。

  • スコーププロバイダーメソッドの場合、各コンポーネントインスタンスは、提供されたオブジェクトのインスタンスを1つ作成します。
  • 対象範囲外のプロバイダメソッドの場合、各コンポーネントインスタンスは、提供する必要があるたびに、提供されたオブジェクトの新しいインスタンスを作成します。

ただし、コンポーネントインスタンスの寿命は重要です。同じコンポーネントの2つの異なるインスタンスは、スコープ付きのものであっても、異なるオブジェクトインスタンスを提供します。

スコープ名は、提供されたオブジェクト(コンポーネントインスタンスのライフタイムと一致する)のライフタイムを示す必要があるため、@PerFragmentは私にとってもっと意味があります。

「MVP Presenters ...」チュートリアルのクイックルックから、作成者の意図が個別のスコープを持つことであるかどうかは明確ではありません。名前は単なる使い捨てなので、あまり読みません。

17
vaughandroid