2016-12-11 7 views
6

Dagger 2を学ぶために、私はアプリケーションを書き直すことにしましたが、以下の問題に対して適切な解決策を見つけることができません。Dagger 2:実行時に提供される依存関係を変更する方法

public interface Mode { 
    Object1 obj1(); 

    //some other methods providing objects for app 
} 

と2つの実装: NormalModeDemoModeこの例の目的のために

は、我々はModeと呼ばれるインターフェースを持っていると仮定しましょう。

モードはシングルトンで保存されるため、アプリケーション内のどこからでもアクセスできます。

public enum ModeManager { 
    INSTANCE,; 

    private Mode mode; 

    public Mode mode() { 
    if (mode == null) 
     mode = new NormalMode(); 
    return mode; 
    } 

    public void mode(Mode mode) { //to switch modules at runtime 
    this.mode = mode; 
    } 
} 

NormalModeは、実行時にDemoModeに切り替えている(のは言わせ、とき時代の背景のカップルのユーザーclickcs)

public void backgroundClicked5Times(){ 
    ModeManager.INSTANCE.mode(new DemoMode()); 
    //from now on every object that uses Mode will get Demo implementations, great! 
} 

ので

最初、私はシングルトンを取り除くととモードを定義してしまいましたダガー2モジュール:

@Module 
public class NormalModeModule { 
    @Provides 
    public Object1 provideObject1() { 
    return new NormalObject1(); 
    } 
} 

@Module 
public class DemoModeModule { 
    @Provides 
    public Object1 provideObject1() { 
    return new DemoObject1(); 
    } 
} 

backgroundClicked5Timesシングルトンを扱う代わりにNormalModeModuleをDAGのDemoModeModuleに置き換えたいので、Object1を必要とする他のクラスは今からDemoObject1の実装を取得します。

ダガーでどうすればいいですか?

ありがとうございます。

+0

ダガーと[スワップ可能なモジュールの可能な複製を2](https://stackoverflow.com/questions/35658488/swappable-modules-with-dagger-2) – tir38

答えて

1

しばらくの間、短剣を試してみたところ、私のユースケースでうまくいくと思われる解決策を思いつきました。

  1. AppComponent

    @Singleton 
    @Component(modules = {AppModule.class, ConfModule.class}) 
    public interface AppComponent { 
        //... 
    } 
    
  2. にモジュールを追加モジュールで

    @Module 
    public class ConfModule { 
        @Provides 
        @Singleton 
        Conf provideConf() { 
        return new Conf(Conf.Mode.NORMAL); 
        } 
    } 
    
  3. Confのシングルトンインスタンスを提供するモード

    public class Conf { 
        public Mode mode; 
    
        public Conf(Mode mode) { 
        this.mode = mode; 
        } 
    
        public enum Mode { 
        NORMAL, DEMO 
        } 
    } 
    
  4. についての状態情報を保持するクラスを定義します。

  5. 単にConfオブジェクトを注入し、それを変更し、実行時にモードを切り替えるにはモード

    @Module 
    public class Object1Module { 
    
        @Provides 
        Object1 provideObject1(Conf conf) { 
        if (conf.mode == Conf.Mode.NORMAL) 
         return new NormalObject1(); 
        else 
         return new DemoObject1(); 
        } 
    } 
    
  6. に基づいて異なるオブジェクトを提供するモジュールを定義:

    public class MyActivity extends Activity { 
        @Inject Conf conf; 
    
        //... 
    
        public void backgroundClicked5Times(){ 
         conf.mode = Conf.Mode.DEMO; 
    
         //if you have dagger objects in this class that depend on Mode 
         //execute inject() once more to refresh them 
        } 
    } 
    
+0

これを行うためのまともな方法のようだが、これは、提供された依存関係dは実行時に)シングルトンですか? –

+1

はい、 '@Singleton'で' provideObject1'に注釈を付けるとうまくいきませんが、反対にこのユースケースではアイデアと矛盾します。実行時にオブジェクトを置き換えたいのであれば、そのようなメソッドを '@ Singleton'でマークすることはできません。 一方、 'NormalObject1'と' DemoObject1'シングルトンを作ることで、依存関係を提供するメソッドが2つ以上のインスタンスを生成しないようにすることができます。 – Marcin

+0

最後の文は私が必要とした情報でした。素晴らしいソリューション、thx :) –