So, I\'m currently redesigning an Android app of mine to use Dagger. My app is large and complicated, and I recently came across the following scenario:
Object A requir
What Jake's post says is perfectly true. That said, we (some of the Google folk who work with Guice and Dagger) are working on an alternative version of "assisted injection" or automatic-factory generation which should be usable by Guice or Dagger or stand-alone - that is, it will generate factory class source code for you. These factory classes will (if appropriate) be injectable as any standard JSR-330 class would. But it is not yet released.
Pending a solution like this, Jake Wharton's approach is advisable.
I just want to add that years passed after this question has been posted and now there is a library called
AssistedInject
which has been created by Jake and friends at Square, to solve the exact same problem and is fully compatible with Dagger 2.
You can find it here: https://github.com/square/AssistedInject
Jake's post is great, but there is more simple way. Google created AutoFactory library for creating factory automatically at compile time.
First, create class A
with @AutoFactory
annotation and @Provided
annotation for injecting arguments:
@AutoFactory
public class A {
private DebugLogger logger;
public A(@Provided DebugLogger logger, int amount, int frequency) {
this.logger = logger;
}
}
Then library creates AFactory
class at compile time. So you need just inject the factory to a constructor of B
class.
public class B {
private final AFactory aFactory;
@Inject
public B(AFactory aFactory) {
this.aFactory = aFactory;
}
public A createA(int amount, int frequency) {
return aFactory.create(amount, frequency);
}
}
What you are talking about is known as assisted injection and is not currently supported by Dagger in any automatic fashion.
You can work around this with the factory pattern:
class AFactory {
@Inject DebugLogger debuggLogger;
public A create(int amount, int frequency) {
return new A(debuggLogger, amount);
}
}
Now you can inject this factory and use it to create instances of A
:
class B {
@Inject AFactory aFactory;
//...
}
and when you need to create an A
with your 'amount' and 'frequency' you use the factory.
A a = aFactory.create(amount, frequency);
This allows for A
to have final
instances of the logger, amount, and frequency fields while still using injection to provide the logger instance.
Guice has an assisted injection plugin which essentially automates the creation of these factories for you. There have been discussion on the Dagger mailing list about the appropriate way for them to be added but nothing has been decided upon as of this writing.
You're having a problem because you are mixing injectables and non injectables in your constructor. The general rules for injection that will save you tons of heartache and keep your code clean are:
Injectables can ask for other injectables in their constructor, but not for newables.
Newables can ask for other newables in their constructor but not for injectables.
Injectables are service type objects, ie objects that do work such as a CreditCardProcessor, MusicPlayer, etc.
Newables are value type objects such as CreditCard, Song, etc.