2016-09-07 15 views
1

ダガー2をテストしたところ、シングルトンアノテーションに関するいくつかの奇妙な動作があります。自分の問題を示すためにいくつかのテストコードを作成しました。複数のインスタンスでダガー2シングルトン

マイモジュール:

public interface ThingA { 
    void showMyId(); 
} 

実装:ダガーを実行

public class ConcreteThingA implements ThingA { 
    @Override 
    public void showMyId() { 
     System.out.println(this); 
    } 
} 

はコード:

public void doStuff() { 
    ThingA thingA=DaggerThingAComponent.create().provideThingA(); 
    ThingA thingB=DaggerThingAComponent.create().provideThingA(); 
    System.out.println("Hello"); 
} 
私はシングルトンにしたいものの

@Module 
public class App { 

    @Provides 
    @Singleton 
    ThingA provideThingA(){ 
     return new ConcreteThingA(); 
    } 

} 

インタフェース

ここでは、2回質問したときに同じインスタンスが取得されないことを示すスクリーンショットです。私は何か基本的なことを逃したのですかThingAは単なる愚かな名前であり、私の実際のアプリケーションでは、私のサービスでこのシングルトンの動作をしたいと考えています。

Debug screenshot

+0

何 'DaggerThingAComponent.create()'のように見えるんガイド?あなたはコンポーネントインスタンスをキャッシュしているのですか、それともそれぞれの呼び出しで新しいインスタンスを作成していますか? –

+1

@EgorNあなたはそれを釘付けにしました。 Daggerはコンポーネントの存続期間内にシングルトンの動作を強制するため、2つのコンポーネントを作成することは、それぞれ独自のシングルトンを持つ2つのアプリケーションを作成することと同じです。 –

答えて

6

トリックはダガーは、コンポーネントを介しスコープ/ライフサイクルを強制することで、あなたはここで2つの別個の構成要素を作成しました:

ThingA thingA = DaggerThingAComponent.create().provideThingA(); 
ThingA thingB = DaggerThingAComponent.create().provideThingA(); 

あなたは新しいトップレベルを作成するたび@ Singleton- Daggerは、@ Singletonオブジェクトごとに新しいコンテナを使用して、新しいオブジェクトグラフを作成します。もちろん

ThingAComponent component = DaggerThingAComponent.create(); 
ThingA thingA = component.provideThingA(); 
ThingA thingB = component.provideThingA(); // thingA == thingB 

、さらに依存関係グラフを介してアクセスするもの全てが同じコンポーネントから来ているので、これはあなたが探しているシングルトン動作を保持します:あなたは代わりに、これを持っている必要があります。多くの場合


、あなたは、コンポーネントの周りを通過する必要はありません:コンポーネントは、トップレベルのコンポーネントを使用する必要があり、インジェクタを介してアクセス可能なものは、それがいけないことを意味する(その依存関係を@Inject必要がありますコンポーネント自体への参照が必要です)。これはDIやDaggerへの移行中に問題が発生する可能性がありますが、複数の@Singletonコンポーネントを作成することは回避できません。代わりに、次のいずれかを試してみてください。

  • あなたが何かの複数のインスタンスが必要な場合、あなたは常にあなたが@Providesメソッドを作成したかどうかProvider<T>の代わりTを注入することができます。特に、オブジェクトの作成が特に重い場合は、特定の依存関係のコピーを1つまたは1つだけ必要とする場合は、Lazy<T>を挿入できます。
  • YourComponent.getTを呼び出すのではなく、@Inject YourComponentではなく、常に@Inject Provider<T> tProviderであることが望ましいですが、オブジェクトグラフ内で深く必要な場合は、コンポーネント自体を@Injectできます。
  • Androidを含む場合によっては、コンポーネントをアプリケーションのインスタンスフィールドとして、または他の場所の静的フィールドとして、グローバルにアクセス可能なフィールドに保存することができます。これは、Androidがグラフから注入されたインスタンスを取得するのではなく、独自にオブジェクトを作成するためです。それ以外の場合は、コンポーネントを渡す必要がないように依存関係を注入します。

も参照してください:ダガー2ユーザーからBindings in the graph

+0

しかし、Daggarが扱うオブジェクトを別の場所から取得するにはどうすればよいですか?私は、アプリケーション全体にコンポーネントインスタンスを渡すことを避けたいと思います... –

+0

@why_vincent代替案を含めるために更新された答え。一般的に、Componentを渡すのではなく、必要な依存関係を注入します。 –

関連する問題