Search code examples
androiddagger-2dagger

Android Dagger and setting a module at arbitrary moment


I am a newbie in using Dagger and DI. I am trying to use AndroidInjection resolver for injecting dependencies into fragments of its activity.

Generally, I understood that, in the case of using Dagger.android, I have to create MyAppComponent and install AndroidInjectionModule in order to use AndroidInjection.inject(Activity/Fragment/etc..). In this way, I have provided Subcomponents' interfaces with Builders to make Dagger able to generate appropriate injectors.

But what if I have Subcomponent, i.e. DeviceFragmentSubcomponent that has a dependency on the module with parameterized constructor?

@Subcomponent(modules = {DeviceModule.class})
public interface DevicePageFragmentSubcomponent extends AndroidInjector<DevicePageFragment>{

    @Subcomponent.Builder
    public abstract class Builder extends AndroidInjector.Builder<DevicePageFragment>{
        public abstract Builder setDeviceModule(DeviceModule deviceModule);
    }
}

@Module
public class DeviceModule {

    private Device mDevice;

    public DeviceModule(Device device) {
        mDevice = device;
    }

    @Provides
    public Device provideDevice(){
        return mDevice;
    }
}

What should be done to set DeviceModule instance within DeviceActivity for using AndroidInjection.inject(this) in its fragments?

Is it possible to add required modules not at the moment of creation application's dependency tree, but on the arbitrary event?


Solution

  • The Android Injection part of Dagger can (currently) only be used along with AndroidInjection.inject(this), where it will inject the given Android Framework type with a predefined module.

    As such, there is no way to pass in a parameter or module.

    Your first option would be not to use the Android Injection part of Dagger. Just create your component as you see fit and inject your object.

    The second option would be to not use a parameter / module. In theory, if your Activity can create a DeviceModule, so can Dagger, given that it has access to the Activity—and by using the Android Injection parts, the component injecting your type has access to it.

    You did not specify what dependency Device has or why you need to pass it to the DeviceModule from your fragment.

    Let's say your Device depends on DevicePageFragment.

    class Device {
      @Inject Device(DevicePageFragment fragment) { /**/ } // inject the fragment directly
    }
    

    You can access the fragment and do what you would do. If that's not your case, let's say you need to read the arguments Bundle. You could modify your Module to not take a device, but rather to create it iself, and getting rid of the constructor argument as well.

    @Module
    public class DeviceModule {
    
      // no constructor, we create the object below
    
      // again we take the fragment as dependency, so we have full access
      @Provides
      public Device provideDevice(DevicePageFragment fragment){
        // read your configuration from the fragment, w/e
        long id = fragment.getArguments().getLong("id")
        // create the device in the module
        return new Device(id);
      }
    }
    

    In the end it really depends on your usecase.


    What I tried to show is that you have access to the object that you are trying to inject. This means that whatever you can do within this object, you can do within Dagger. There is no need for parameterized modules, since you can extract those parameters from the target, as seen above.