How can I describe Dagger 2, which implementation should I create based on X?

Inside the module, if I need to provide a different implementation of the interface based on the variable known at the time the module was built, I can put the logic inside the @Provides method for this type of interface. For instance:

@Module public class FooModule { private final State state; public FooModule(State state) { this.state = state; } @Provides FooInterface provideFooImplementation() { switch(state) { case STATE_1: return new FooImpl1(); case STATE_2: return new FooImpl2(); ... case STATE_10: return new FooImpl10(); } } } 

However, these implementations can be created with a dagger. I would say, "Hey, based on X, I want you to create this class for me."

I have considered several options.

  • Change the rendering method to use all possible implementations:

     @Provides FooInterface provideFooImplementation(FooImpl1 impl1, FooImpl2 imp2, ..., FooImpl10 impl10) { switch(state) { case STATE_1: return impl1; case STATE_2: return impl2; ... case STATE_10: return impl10; } } 

This allows the dagger to create them and satisfy all their dependencies, but it is not a good idea if each of the implementations is relatively large or expensive to create.

  1. Modify the rendering method to collectively take all the dependencies for different implementations.

     @Provides FooInterface provideFooImplementation(Context context, Repo repo, HttpClient httpClient, ...) { switch(state) { case STATE_1: return new FooImpl1(context); case STATE_2: return new FooImpl2(repo, httpClient); ... case STATE_10: return new FooImpl10(context, repo); } } 

This is slightly better than option 1 in that the Dagger should not create an instance of each individual implementation, but it still needs to create instances of all the dependencies, even if they cannot be used in all cases. I will also return to creating objects myself, even if they can be created with a dagger.

  1. Create one module for each implementation and create the corresponding module. So something like:

     @Module public FooImpl1Module { @Provides FooInterface provideFooImplementation(Context context) { return new FooImpl1(context); } } 

This will be fine, but now I have problems defining a component that depends on the module.

What is the best way to solve this problem?

One suggestion was to try option 1 with parameters wrapped in Lazy. Then I end up calling .get () on one. I will try it when I can, and publish the results

+6
source share
3 answers

Instead of Lazy<T> run option 1 with Provider<T> . Lazy<T> is just a Provider<T> that memoizes locally (with the necessary double check lock), but since you know that you will only call one provider exactly once, you can simply enter the Provider instead and skip synchronization overhead.

 @Provides FooInterface provideFooImplementation( Provider<FooImpl1> impl1, Provider<FooImpl2> impl2, ..., Provider<FooImpl10> impl10) { switch(state) { case STATE_1: return impl1.get(); case STATE_2: return impl2.get(); ... case STATE_10: return impl10.get(); } } 

Option 2 will work, but you will effectively skip dependency posting, which Dagger can easily do for you, and option 3 will not work as indicated, because your @Component annotation requires your list of modules to be compile time constant for code generation Dagger.

(Variant of Variant 3 may work if your binding was connected with a constant or a zero dependency class of one form or another, because then you could pass an arbitrary subclass of your module into your component linker. However, the dagger can analyze the bindings in the superclass module, and you will have problems if your implementations of the @Provides method take different parameters, like yours, so switch is the best and clear alternative that I can think of.)

+1
source

A possible solution would be to use the @Named("foo") annotation combined with the advantage of the component provision method over manual introduction, which, however, means that your state will be independent of the module itself and you will be the one to make your choice

 @Component(modules={FooModule.class}) public interface AppComponent { @Named("STATE_1") FooInterface fooImpl1(); @Named("STATE_2") FooInterface fooImpl2(); ... @Named("STATE_10") FooInterface fooImpl10(); } @Module public FooImpl1Module { @Provides @Named("STATE_1") FooInterface provideFooImpl1(Context context) { return new FooImpl1(context); } @Provides @Named("STATE_2") FooInterface provideFooImpl2(Context context) { return new FooImpl2(context); } ... @Provides @Named("STATE_10") FooInterface provideFooImpl10(Context context) { return new FooImpl10(context); } } 

Then you can call

 FooInterface fooInterface = component.fooImpl1(); 
+3
source

Have you tried something like this?

 public class hectic extends Iam { String tokenizer heccas = new string tokenizer(); } 
-4
source

All Articles