How to inject using interface in dagger2 - android

Considering the following structure:
public class WaterWorld implements IWorld {
...
#Inject
CreationMode creationMode;
#Override
public final void init() {
WorldModule.getComponent().inject(this);
}
...
}
Is it possible for WaterWorld to get dependencies if the Component has following structure:
void inject(IWorld world);
I am getting null this way. However, if I try to do it in the following
void inject(WaterWorld world);
then it works. However, I have many classes implementing IWorld. I wanted to do it this way: void inject(IWorld world); How to do this or is there some other generic solution?

No, Dagger will always inject the class specified in the inject(Foo foo) method. It will inject objects in the parent types, but it will not inject objects in subclasses.
Dagger uses the type specified to generate code for the injection, but if you don't specify the specific class then Dagger simply doesn't know about it and won't inject its fields.
Note: You don't give any specific example, but it looks like you could be very well using constructor injection instead, which has no need for manual injection or inject methods in your component. If you have multiple implementations of the same interface you might even take a look at multi bindings with Dagger.

Related

How to use #Qualifers for multiple instances of same type with Dagger 2? [duplicate]

This is a Canonical Question because this is a common error with Dagger 2.
If your question was flagged as a duplicate please read this post carefully and make sure to understand what this error means and why it occured. If this post does not work for you make sure to include where and how you provide the mentioned classes and include the full error message in your question like the one here.
I tried to use a dependency with Dagger 2, but I receive the following error when I try to compile my project:
error: com.example.MyDependency cannot be provided without an #Inject constructor or from an #Provides-annotated method.
com.example.MyDependency is provided at
com.example.MyComponent.myDependency()
What does this mean and how can I fix it?
I have a component and tried to provide a dependency. My basic setup looks like this:
// this is the dependency I try to use
class MyDependency {}
#Component
interface MyComponent {
// I want to make it accessible to be used with my component
MyDependency myDependency();
}
tl;dr You forgot to either add an #Inject to your constructor so that Dagger can use Constructor Injection to provide the object, or you need some method in one of your Modules that creates or binds the object.
What's going on?
Have a good look at the error message: It states that you try to request a dependency but Dagger has no way to provide or create it. It simply does not know how to, because it cannot be provided without an #Inject constructor or from an #Provides-annotated method.
A close look at the error message shows the class (a) that you are trying to provide and the component (b) that needs it.
com.example.MyDependency (a) is provided at
com.example.MyComponent.myDependency() (b)
You have to make sure that (b) can create or provide (a) to fix your issue.
It looks a bit more complex if you tried to inject your dependency somewhere else, but you can still see the full stack of events—in this case a constructor injection missing a dependency. The class (a) that you are trying to provide and the location (b) where Dagger tried injecting it. It also tells you where that dependent class was created (c) and again the component (d) that failed providing (a).
com.example.MyDependency cannot be provided without an #Inject constructor or from an #Provides-annotated method.
com.example.MyDependency (a) is injected at
com.example.DependentClass.(dependency) (b)
com.example.DependentClass is provided at (c)
com.example.MyComponent.myDependency() (d)
The same applies here: Make sure that (d) knows how to provide (a) and you're good to go.
How do I fix this?
Have a look at the error as shown above. Make sure you understand where it occured and what you are trying to inject. Then tell Dagger how to provide your object.
an #Inject constructor
As the error states, you try to use MyDependency but MyComponent does not know how to do that. If we have a look at the example it becomes clear why:
class MyDependency {}
The class has no #Inject annotated constructor! And there is no other module in the component, so there is nothing Dagger could do.
If you want to use constructor injection you can just add an #Inject annotated constructor and are done. Dagger will see this constructor and know how to create your class.
class MyDependency {
#Inject
MyDependency() { /**/ }
}
That is all you have to do when you can make use of constructor injection.
from an #Provides-annotated method
The error message states a second option, which allows you to provide an object if you don't want—or can't—use constructor injection. You can also add a #Provides annotated method to a module and add this module to your component.
#Module
class MyModule {
#Provides
MyDependency provideMyDependency() {
return new MyDependency();
}
}
#Component(modules = MyModule.class)
interface MyComponent {
MyDependency myDependency();
}
This way Dagger can use your module to create and provide your dependency. It is a little bit more boilerplate than using Constructor Injection, but you will have to use Modules for everything that needs further setup or that does not have an annotated constructor, e.g. third party libraries like Retrofit, OkHttp, or Gson.
There are also other ways to provide a dependency from a component. A #SubComponent has access to its parents dependencies, and a component dependency can expose some of its dependencies to its dependent components. But at some point everything Dagger provides needs to either have an #Inject constructor or a Module providing it.
But I did add MyDependency!
Pay close attention to the details. You probably are using an interface when you are only providing the implementation, or try to use a parent class when Dagger only knows about the subclass.
Maybe you added a custom #Qualifier or used #Named("typeA") with it. To Dagger this is a completely different object! Double check that you actually provide and request the same dependency.
Read the error and make sure that you either have an #Inject annotated constructor, a module that has a #Provides method that provides that type, or a parent component that does.
What if I want to provide an implementation for my interface?
A simple example like the following shows how one class extends another:
class MyDependency extends MyBaseDependency {
#Inject MyDependency() { super(); }
}
This will inform Dagger about MyDependency, but not about MyBaseDependency.
If you have one class implementing an interface or extending a super class you have to declare that. If you provide MyDependency this does not mean that Dagger can provide MyBaseDependency. You can use #Binds to tell Dagger about your implementation and provide it when the super class is required.
#Module
interface MyModule {
#Binds
MyBaseDependency provideMyBaseDependency(MyDependency implementation);
}

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?
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.

Android | Dagger 2. Injecting different subclasses into Fragment depending of a condition

I am working with MVP and Dagger 2 DI. I have a Fragment that I reuse in a few activities. I have an interface type for presenter as a property of the Fragment, say MVPPresenter. Depending in which activity the Fragment is being used, I need to inject different presenters into it (each presenter is an implementation of MVPPresenter). So I need a way to inject each implementation of MVPPresenter into the Fragment as I need.
Currently, I have a terrible solution, which works, but it is simply wrong and creates unnecessary objects that are never used. Here is the code:
public class MyFragment {
...
#Inject
public void setPresenter(#NonNull ProfilePresenter presenter) {
if (mAdapter instanceof ProfileAdapter) {
this.presenter = presenter;
}
}
#Inject
public void setPresenter(#NonNull ContactsPresenter presenter) {
if (mAdapter instanceof ContactsAdapter) {
this.presenter = presenter;
}
}
...
}
Here is my Module:
#Module
class PresentersModule {
#Provides
#Singleton
ProfilePresenter ProfilePresenter() {
return new ProfilePresenter();
}
#Provides
#Singleton
ContactsPresenter ContactsPresenter() {
return new ContactsPresenter();
}
}
You see, depending on Adapter type, I assign presenter, or do not. I know this is stupid and all. Problem is that Dagger needs exact type to inject to be specified and Interface type wont work.
What is the proper way of dealing with such cases?
You have, as I see it, three solutions of varying degrees of weight.
Inject two choices as you have now: If you know all of your Fragment's use-cases up front, and you don't need to vary the dependency graphs any more than on a single class, you can do so easily using a similar method to what you have now. My variant uses Providers, which are bound automatically for any object in your graph, so that you don't unnecessarily create whole trees of objects; also, #Inject methods can take an arbitrary parameter list, so you can do all of your method injection in one method if you choose.
#Inject
public void setPresenter(
#NonNull Provider<ContactsPresenter> contactsPresenterProvider,
#NonNull Provider<ProfilePresenter> profilePresenterProvider) {
if (mAdapter instanceof ContactsAdapter) {
this.presenter = contactsPresenterProvider.get();
} else if (mAdapter instanceof ProfileAdapter) {
this.presenter = profilePresenterProvider.get();
}
}
The other two solutions involve multiple components: Instead of saying "there is one way of binding my graph together", you're effectively asking Dagger to generate multiple options for you, which means that your graphs can vary widely but stay consistent. This technique might be more useful if you reuse objects in different ways for different sections of your application, like if you have a Profile section and a Contacts section, each of which using a common A injecting a common B injecting a common C injecting a different D. To consistently support two deep graphs like that, child components are a much better option.
Use component dependencies: As in rst's answer, you can use component dependencies to isolate your fragments. They did a pretty good job of explaining, so I'll not repeat that here. You should be aware, though, that component dependencies can only consume bindings that are exposed on the component you depend on: Even if Foo and Bar are bound on DiComponent, you won't be able to access them from your ProfileComponent or ContactsComponent unless you put Foo getFoo() and Bar getBar() on your DiComponent. (That said, component dependencies don't have to be Dagger components, either; they can be arbitrary types that you implement yourself or let Dagger implement for you.)
Use subcomponents: Though rst alluded to subcomponents, I think they warrant a bit more explaining, particularly because they are a core component of the recently-released dagger.android functionality, and because Fragments and other UI pieces can be difficult to extract with component dependencies—subcomponents implicitly and automatically inherit bindings from the surrounding component, so you don't have to explicitly expose bindings on your DiComponent. See other differences at this SO question.
#Component
public interface DiComponent {
ProfileComponent getProfileComponent(); // Dagger generates implementations
ContactsComponent getContactsComponent(); // as part of DiComponent.
}
#Subcomponent(modules={ContactsModule.class})
public interface ContactsComponent {
void inject(MyFragment myFragment);
}
#Module
public interface ContactsModule {
#Binds MvpPresenter bindMvpPresenter(ContactsPresenter contactsPresenter);
}
#Subcomponent(modules={ProfileModule.class})
public interface ProfileComponent {
void inject(MyFragment myFragment);
}
#Module
public interface ProfileModule {
#Binds MvpPresenter bindMvpPresenter(ProfilePresenter profilePresenter);
}
In the above, the root DiComponent doesn't have a binding for MvpPresenter, so in itself it can't inject MyFragment. However, ProfileComponent and ContactsComponent can, and each will use different graphs configured in the corresponding Modules (but silently inheriting common bindings from DiComponent's modules). If the graphs vary differently further down, like with each MvpPresenter using the same Validator but with a different ProfileValidationRule versus ContactsValidationRule, you could bind ValidationRule to those different classes in your different Modules to get different behavior.
(For completeness, you would usually also have the option to use a factory like AutoFactory and pass in a parameter like the presenter to your specific container like Fragment. However, this is only really an option if you're creating your instances, and not really an option when Android forces a zero-arg public constructor so it can create Fragment instances at will.)
Looking through the names you've given to mvp-presenters, one could conclude, their complementary mvp-views should rather be separated and implemented in different fragments.
But if you wish to maintain things as-is, having only single setPresenter method declared in your fragment, probably the easiest way to deal with your problem would be to introduce separate components with complementary modules for providing desirable presenter implementations.
For this solution to work you would need to adjust your fragment to contain single declaration of setPresenter method with MVPPresenter type as an argument:
#Inject
public void setPresenter(#NonNull MVPPresenter presenter) {
this.presenter = presenter;
}
Afterwards, you'd need to provide components exposing inject(...) method and declaring usage of appropriate module. As those dependency graphs would be dependent on main component instance, they should get their own scope (tied to activity or fragment, depending on what class is actually holding the graph object).
For instance, if you were using DiComponent for providing all your dependencies with scope defined via #Singleton annotation, you'd need to declare #MyFragmentScope annotation and provide components, dependent on above-mentioned DiComponent, in order to declare injectable presenters:
import javax.inject.Scope;
#Scope
public #interface MyFragmentScope {
}
Your dependent components would look like:
#MyFragmentScope
#Component(dependencies = DiComponent.class, modules = ProfileModule.class)
public interface ProfileComponent {
void inject(MyFragment fragment);
}
with complementary module:
#Module
public class ProfileModule {
#Provides
#MyFragmentScope
MVPPresenter providesProfilePresenter() {
return new ProfilePresenter();
}
}
Note: return type is MVPPresenter, not concrete implementation.
Similarly you'd need to create ContactsComponent and ContactsModule for your ContactsPresenter.
Eventually you should use proper component instance to perform the injection. Now instead of using
diComponent.inject(myFragment)
you should use component which would provide desirable dependency.
At this point you would actually have a switch defining which presenter should be used.
In case of ProfilePresenter injecting you'd need to use:
DaggerProfileComponent.builder()
.diComponent(diComponent)
.build()
.inject(myFragment);
Or in case of ContactsPresenter injecting you'd need to use:
DaggerContactsComponent.builder()
.diComponent(diComponent)
.build()
.inject(myFragment);
It's rather common practice to use separate components for smaller parts of application like activities. It's possible to either declare such components as regular dependent ones or as sub components (see #Subcomponent documentation for reference). Starting from Dagger 2.7 there is a new way of declaring Subcomponents via #Module.subcomponents. Due to this fact there's an opportunity to decouple AppComponent from Activities Subcomponents. You may refer to sample GitHub repository from frogermcs for reference. He also has a great complementary blog post on this topic.

How to migrate missing inject from module with complete = false from Dagger 1 to Dagger 2

I have a library project/module that is used by both Android apps and regular java apps.
In Dagger 1 this project/module has property complete = false. Within there is an #Inject field that is not satisfied by any class implementation or #Provides method. The idea is to force the "top" module(s) which has complete = true to provide system specific implementation
Just for the sake of example: In the library project I have ActLogin activity that have field #Inject #Named("app version") mAppVersion. The value of this field is used when logging in into a server. ActLogin is used by several apps that use this library. Each app's module has complete = true and provides value with #Provides #Named("app version") provideAppVersion()
Documentation for migration of Dagger 2 (http://google.github.io/dagger/dagger-1-migration.html) states:
Dagger 2 modules are all declared as complete = false and library = true
and in the same time the "main" documentation page (http://google.github.io/dagger/) states:
The Dagger annotation processor is strict and will cause a compiler error if any bindings are invalid or incomplete.
The latter is obviously the correct one because when trying to build with unsatisfied inject error is produced (error: java.lang.String cannot be provided without an #Provides- or #Produces-annotated method).
The question is: is it possible to migrate this approach (deferring providing inject) to Dagger 2 and how?
P.S. Initially I thought as a dirty workaround to provide some dummy values in the library's #Module but then again - you cannot have module overrides in Dagger 2 (which is kind of WTF(!!!). Module overrides were the most useful feature for me when creating unit tests). Probably I am missing something very basic and I hope that someone can point it out :-).
It turns out that there is dedicated construct for this but it takes some time to find it out.
If you need to have a component that have a module which contains unsatisfied inject(s) - make it #Subcomponent. As documentation clearly states:
That relationship allows the subcomponent implementation to inherit the entire binding graph from its parent when it is declared. For that reason, a subcomponent isn't evaluated for completeness until it is associated with a parent
So in my case, my library project needs to be a dagger subcomponent. When I use it in my app project, my app dagger component have to include the lib subcomponent.
In code:
The library subcomponent:
#Subcomponent(modules = Mod1.class)
public interface MyLibraryComponent {
void inject(Mod1Interface1 in);
}
The app component:
#Component(modules = Mod2.class)
#Singleton
public interface MyAppComponent {
void inject(MainActivity act);
MyLibraryComponent newMyLibraryComponent();
}
Please note the MyLibraryComponent newMyLibraryComponent(); - that is how you tell dagger that your component contains that subcomponent.
Graph instantiation:
MyAppComponent comp = DaggerMyAppComponent.builder().build();
Please note that contrary to using component composition with dependencies (#Component's property) in this case you don't have to "manually" construct your subcomponent. The component will "automatically" take care for that in case the subcomponent's modules don't need special configuration (i.e. constructor parameters). In case some subcomponent's module requires configuration you do it trough the component instantiation like this:
MyAppComponent comp = DaggerMyAppComponent.builder().
mod2(new Mod2SpecialConfiguration()).
build();
For android there is a special twist if your library project contains activities because each activity have to be separately injected "on demand" contrary to regular java application where you usually inject the whole application once at start up time.
For the sake of example let's say our library project contains login activity "ActLogin" that we use as common for several applications.
#Subcomponent(modules = Mod1.class)
public interface MyLibraryComponent {
void injectActLogin(ActLogin act);
void inject(Mod1Interface1 in);
}
The problem is that in Android we usually create our dependency graph in the Application object like this:
public class MyApplication extends Application {
private MyAppComponent mAppDependencyInjector;
#Override
public void onCreate() {
super.onCreate();
mAppDependencyInjector = DaggerMyAppComponent.builder().build();
}
public MyAppComponent getAppDependencyInjector() {
return mAppDependencyInjector;
}
}
and then in your activity you use it like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
// ...
((MyApplication) getApplication()).getAppDependencyInjector().inject(this);
// ...
}
but our ActLogin activity is part of the library project (and dagger component) that is not event aware of what application will it be used in so how are we going to inject it?
There is a nice solution but please note that I am not sure it is canonical (i.e. it is not mentioned in the documentation, it is not given as an example by the "authorities" (afaik))
Project's source can be found at github.
First you will have to extend the library dagger component in you app component:
public interface MyAppComponent extends MyLibraryComponent {
That way your app component will contain all the inject methods from the subcomponent so you will be able to inject it's activities too. After all, top component is in fact the whole object graph (more precisely the Dagger generated DaggerMyAppComponent represent the whole graph) so it is able to inject everything defined in itself + in all subcomponents.
Now we have to assure that the library project is able to access it. We create a helper class:
public class MyLibDependencyInjectionHelper {
public static MyLibraryComponent getMyLibraryComponent(Application app) {
if (app instanceof MyLibraryComponentProvider) {
return ((MyLibraryComponentProvider) app).getMyLibraryComponent();
} else {
throw new IllegalStateException("The Application is not implementing MyLibDependencyInjectionHelper.MyLibraryComponentProvider");
}
}
public interface MyLibraryComponentProvider {
MyLibraryComponent getMyLibraryComponent();
}
}
then we have to implement MyLibraryComponentProvider in our Application class:
public class MyApplication extends Application implements
MyLibDependencyInjectionHelper.MyLibraryComponentProvider {
// ...
#Override
public MyLibraryComponent getMyLibraryComponent() {
return (MyLibraryComponent) mAppDependencyInjector;
}
}
and in ActLogin we inject:
public class ActLogin extends Activity {
#Override
public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
// ...
MyLibDependencyInjectionHelper.getMyLibraryComponent(getApplication()).
injectActLogin(this);
// ...
}
}
There is a problem with this solution: If you forget to implement the MyLibraryComponentProvider in your application you will not get an error at compile time but at runtime when you start ActLogin activity. Luckily that can be easily avoided with simple unit test.

Using Dagger for dependency injection on constructors

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 requires a special DebugLogger instance which is a perfect candidate for injection. Instead of passing around the logger I can just inject it through A's constructor. This looks something like this:
class A
{
private DebugLogger logger;
#Inject
public A(DebugLogger logger)
{
this.logger = logger;
}
// Additional methods of A follow, etc.
}
So far this makes sense. However, A needs to be constructed by another class B. Multiple instances of A must be constructed, so following Dagger's way of doing things, I simple inject a Provider<A> into B:
class B
{
private Provider<A> aFactory;
#Inject
public B(Provider<A> aFactory)
{
this.aFactory = aFactory;
}
}
Ok, good so far. But wait, suddenly A needs additional inputs, such as an integer called "amount" that is vital to its construction. Now, my constructor for A needs to look like this:
#Inject
public A(DebugLogger logger, int amount)
{
...
}
Suddenly this new parameter interferes with injection. Moreover, even if this did work, there would be no way for me to pass in "amount" when retrieving a new instance from the provider, unless I am mistaken. There's several things I could do here, and my question is which one is the best?
I could refactor A by adding a setAmount() method that is expected to be called after the constructor. This is ugly, however, because it forces me to delay construction of A until "amount" has been filled in. If I had two such parameters, "amount" and "frequency", then I would have two setters, which would mean either complicated checking to ensure that construction of A resumes after both setters are called, or I would have to add yet a third method into the mix, like so:
(Somewhere in B):
A inst = aFactory.get();
inst.setAmount(5);
inst.setFrequency(7);
inst.doConstructionThatRequiresAmountAndFrequency();
The other alternative is that I don't use constructor-based injection and go with field-based injection. But now, I have to make my fields public. This doesn't sit well with me, because now I am obligated to reveal internal data of my classes to other classes.
So far, the only somewhat elegant solution I can think of is to use field-based injection for providers, like so:
class A
{
#Inject
public Provider<DebugLogger> loggerProvider;
private DebugLogger logger;
public A(int amount, int frequency)
{
logger = loggerProvider.get();
// Do fancy things with amount and frequency here
...
}
}
Even still, I'm unsure about the timing, since I'm not sure if Dagger will inject the provider before my constructor is called.
Is there a better way? Am I just missing something about how Dagger works?
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.
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.
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.
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);
}
}
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
Dagger 2 now has support for assisted injection which should help solve your usecase.
https://dagger.dev/dev-guide/assisted-injection
You can wrap your class like this:
#AssistedInject
public A(DebugLogger logger, #Assisted int amount)
{
...
}
Create a factory for this class.
#AssistedFactory
public interface MyDataFactory {
A create(int amount);
}
and in your client, you can use:
#Inject MyDataFactory dataFactory;
void setupA(int amount) {
A a = dataFactory.create(config);
// ...
}

Categories

Resources