Dagger 2: how to change provided dependencies at runtime

南笙酒味 提交于 2019-12-05 01:44:53

Having experimented with dagger for a while I came up with solution that seems to be working well in my use case.

  1. Define class that will hold state information about mode

    public class Conf {
      public Mode mode;
    
      public Conf(Mode mode) {
        this.mode = mode;
      }
    
      public enum Mode {
        NORMAL, DEMO
      }
    }
    
  2. Provide singleton instance of Conf in Module

    @Module
    public class ConfModule {
      @Provides
      @Singleton
      Conf provideConf() {
        return new Conf(Conf.Mode.NORMAL);
      }
    }
    
  3. Add module to AppComponent

    @Singleton
    @Component(modules = {AppModule.class, ConfModule.class})
    public interface AppComponent {
        //...
    }
    
  4. Define modules that provide different objects based on Mode

    @Module
    public class Object1Module {
    
      @Provides
      Object1 provideObject1(Conf conf) {
        if (conf.mode == Conf.Mode.NORMAL)
          return new NormalObject1();
        else
          return new DemoObject1();
      }
    }
    
  5. To switch mode at runtime simply inject Conf object and modify it:

    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
        }
    }
    

Maybe you can consider using multibindings?

@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();
  }
}

and when using Mode:

@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!
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!