为了学习Dagger 2,我决定重写我的应用程序,但我仍然坚持为以下问题寻找合适的解决方案。
出于本示例的目的,我们假设我们有一个名为Mode
的接口:
public interface Mode {
Object1 obj1();
//some other methods providing objects for app
}
和两个实现:
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!
}
首先,我摆脱了单身,并将模式定义为Dagger 2模块:
@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
的类就会获得{ {1}}从现在开始实施。
我怎么能在Dagger中做到这一点?
提前致谢。
答案 0 :(得分:3)
我已经尝试了一段时间的匕首,我想出了一个似乎在我的用例中运行良好的解决方案。
定义将保存有关模式的状态信息的类
public class Conf {
public Mode mode;
public Conf(Mode mode) {
this.mode = mode;
}
public enum Mode {
NORMAL, DEMO
}
}
在Module
中提供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
}
}
答案 1 :(得分:0)
也许您可以考虑使用多重绑定?
@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!
}