2

I need to inject fields of an instance of one of my classes on-demand i.e., at runtime because I'm instantiating them on-the-fly.

I used to use Guice for this where I would call MembersInjector#injectMembers or Injector#injectMembers. How can I have something like this in Dagger 2?

David Rawson
  • 20,912
  • 7
  • 88
  • 124
Nicolas Sagala Beaucage
  • 1,229
  • 1
  • 11
  • 23

2 Answers2

7

Dagger 2 Components are the counterpart to Guice Injectors so the way to do this in Dagger 2 would be to specify the object whose field you want to inject at runtime as an injection site and request injection from the component.

Let's say you have a CoffeeShop with fields you want to inject:

class CoffeeShop {

    @Inject CoffeeMaker coffeeMaker;

    CoffeeShop() { 
        //we're not using constructor injection here 
        //although we probably should be :/
    }
}

You can specify CoffeeShop as an injection site inside a component and request injection from it:

@Component(modules = { CoffeeModule.class })
interface CoffeeComponent {
    void inject(CoffeeShop coffeeShop);
}

So inside another class you can do something like this:

private CoffeeComponent coffeeComponent;

void initComponent() {
    coffeeComponent = DaggerCoffeeComponent
                         .builder()
                         .coffeeModule(new CoffeeModule())
                         .build();
}

void makeCoffee() {  
    CoffeeShop coffeeShop = new CoffeeShop();
    coffeeComponent.inject(coffeeShop); //inject members of coffeeShop
    coffeeShop.makeCoffee();
}

Alternatively, you can define provision methods inside your Dagger 2 Components which will allow you to resolve instances of a class ad hoc.

If you look at Jeff Bowman's example in the linked question, you can see there is a Component like this:

@Component(modules = {/* ... */})
public interface CoffeeShopComponent {
  CoffeeShop getCoffeeShop();

  void inject(CoffeeService serviceToInject); // to be discussed below
}

Say you then have a CoffeeService. You can now call getCoffeeShop() to obtain arbitrary instances of CoffeeShop:

class CoffeeService extends SomeFrameworkService {

    private CoffeeComponent coffeeComponent;

    void initComponent() {
        coffeeComponent = DaggerCoffeeComponent
                              .builder()
                              .coffeeModule(new CoffeeModule());
                              .build();
    }

    public CoffeeShop createCoffeeShop() {
        return coffeeComponent.getCoffeeShop(); //equivalent to Injector.getInstance();
    }
}
Community
  • 1
  • 1
David Rawson
  • 20,912
  • 7
  • 88
  • 124
1

I don't know that Dagger2 supported @BindsInstance in @Subcomponent.Factory or @Component.Factory at the time when this question was posted but anyway for now, the best approach to inject an instance in runtime seems to be using those.

In Dagger2 tutorial, there is an example(https://dagger.dev/tutorial/10-deposit-after-login) to create a subcomponent receiving an instance.

jyshin
  • 841
  • 1
  • 8
  • 15