Dagger 2を学ぶために、アプリケーションを書き直すことにしましたが、次の問題の適切な解決策を見つけるのに苦労しています。
この例では、Mode
というインターフェイスがあると仮定します。
_public interface Mode {
Object1 obj1();
//some other methods providing objects for app
}
_
および2つの実装:NormalMode
およびDemoMode
。
モードはシングルトンで保存されるため、アプリケーション内のどこからでもアクセスできます。
_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
に切り替えられます(たとえば、ユーザーがバックグラウンドで数回クリックした場合)
_public void backgroundClicked5Times(){
ModeManager.INSTANCE.mode(new DemoMode());
//from now on every object that uses Mode will get Demo implementations, great!
}
_
そこで、最初にシングルトンを取り除き、モードをDagger2モジュールとして定義しました。
_@Module
public class NormalModeModule {
@Provides
public Object1 provideObject1() {
return new NormalObject1();
}
}
@Module
public class DemoModeModule {
@Provides
public Object1 provideObject1() {
return new DemoObject1();
}
}
_
ここで、メソッド_backgroundClicked5Times
_で、シングルトンを処理する代わりに、DAGでNormalModeModule
をDemoModeModule
に置き換えて、_Object1
_を必要とする他のクラスが_DemoObject1
_これからの実装。
Daggerでそれを行うにはどうすればよいですか?
前もって感謝します。
しばらくの間短剣を試してみて、私のユースケースでうまく機能しているように見える解決策を思いつきました。
モードに関する状態情報を保持するクラスを定義します
public class Conf {
public Mode mode;
public Conf(Mode mode) {
this.mode = mode;
}
public enum Mode {
NORMAL, DEMO
}
}
モジュールでConf
のシングルトンインスタンスを提供します
@Module
public class ConfModule {
@Provides
@Singleton
Conf provideConf() {
return new Conf(Conf.Mode.NORMAL);
}
}
AppComponentにモジュールを追加します
@Singleton
@Component(modules = {AppModule.class, ConfModule.class})
public interface AppComponent {
//...
}
モードに基づいて異なるオブジェクトを提供するモジュールを定義する
@Module
public class Object1Module {
@Provides
Object1 provideObject1(Conf conf) {
if (conf.mode == Conf.Mode.NORMAL)
return new NormalObject1();
else
return new DemoObject1();
}
}
実行時にモードを切り替えるには、Conf
オブジェクトを挿入して変更するだけです。
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
}
}
たぶん、マルチバインディングの使用を検討できますか?
@Module
public class NormalModeModule {
@Provides
@IntoMap
@StringKey("normal")
public Object1 provideObject1() {
return new NormalObject1();
}
}
@Module
public class DemoModeModule {
@Provides
@IntoMap
@StringKey("demo")
public Object1 provideObject1() {
return new DemoObject1();
}
}
モードを使用する場合:
@Inject
Map<String, Mode> modes;
//or you perfer lazy initialization:
Map<String, Provider<Mode>> modes;
public void backgroundClicked5Times(){
ModeManager.INSTANCE.mode(modes.get("demo"));
//if you are using Provider:
ModeManager.INSTANCE.mode(modes.get("demo").get());
//from now on every object that uses Mode will get Demo implementations, great!
}