Dependency injection 匕首2:如何在运行时更改提供的依赖项
为了学习Dagger2,我决定重写我的应用程序,但我一直在为下面的问题寻找合适的解决方案 在本例中,我们假设有一个名为Dependency injection 匕首2:如何在运行时更改提供的依赖项,dependency-injection,dagger-2,Dependency Injection,Dagger 2,为了学习Dagger2,我决定重写我的应用程序,但我一直在为下面的问题寻找合适的解决方案 在本例中,我们假设有一个名为Mode的接口: public interface Mode { Object1 obj1(); //some other methods providing objects for app } 和两个实现: NormalMode和DemoMode 模式存储在singleton中,因此可以从应用程序中的任何位置访问它 public enum ModeManag
Mode
的接口:
public interface Mode {
Object1 obj1();
//some other methods providing objects for app
}
和两个实现:
NormalMode
和DemoMode
模式存储在singleton中,因此可以从应用程序中的任何位置访问它
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
(比方说,当用户在后台多次单击cs时)
首先,我去掉了单例,将模式定义为Dagger 2模块:
@Module
public class NormalModeModule {
@Provides
public Object1 provideObject1() {
return new NormalObject1();
}
}
@Module
public class DemoModeModule {
@Provides
public Object1 provideObject1() {
return new DemoObject1();
}
}
现在,在方法backgroundclicked5次
中,我想用DAG中的DemoModeModule
替换NormalModeModule
,这样其他需要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);
}
}
@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!
}
@Inject
地图模式;
//或者您更喜欢延迟初始化:
地图模式;
公开作废背景点击5次(){
ModeManager.INSTANCE.mode(modes.get(“demo”);
//如果您使用的是提供商:
ModeManager.INSTANCE.mode(modes.get(“demo”).get();
//从现在起,每个使用模式的对象都将得到演示实现,太棒了!
}
的可能副本似乎是一个不错的方法,但当提供的依赖项(在运行时将被替换)是单例时,它就不起作用了,是吗?是的,如果您用@singleton
注释provideObject1
,它就不起作用,但另一方面,它与本用例中的想法相矛盾。如果要在运行时替换对象,则不能使用@Singleton
标记此类方法。另一方面,您可以将NormalObject1
和DemoObject1
设置为单例,这样提供依赖项的方法不会创建超过2个实例。最后一句话就是我需要的信息。很好的解决方案,thx:)这正是我想要的。但是你能详细解释一下最后一句话吗?“如果这个类中有dagger对象依赖于模式execute inject()再次刷新它们”。我喜欢这个想法,把模块当作一个配置
@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!
}