Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injecting Generics in Dagger

Is it possible in Dagger to do something like the following:

public abstract class Presenter<T extends BaseView> {

    @Inject T mView;

    public void showLoadingIndicator() {
        mView.showLoading();
    }

}

(example module)

public class MyModule {
    private MyView mView; //extends BaseView

    public MyModule(MyView view) {
        mView = view;
    }

    @Provides
    public BaseView provideView() {
        return mView;
    }

}

And then create an object graph with the module above and inject the view into the presenter?

My attempts have not worked (usually get "unknown class 'T'" sort of errors). I'm not sure if my configuration is wrong or if this is unsupported functionality.

like image 530
loeschg Avatar asked Jan 29 '15 21:01

loeschg


People also ask

What does @inject do dagger?

Declaring Dependencies It uses the javax. inject. Inject annotation to identify which constructors and fields it is interested in. Use @Inject to annotate the constructor that Dagger should use to create instances of a class.

How do you inject value at runtime in dagger?

Inject values at runtime with UI in Dagger2:pureMathModule("Book Name") . build() . inject(this); The difference between DaggerComponent create() and in build() is - create() works when no runtime argument is passed into the constructor, else we use build() method.

What is @module annotation in dagger?

This function is denoted by the @Provides annotation which tells Dagger that it should use this function when providing a GithubService dependency. The framework is essentially looking for the annotation followed by the return type to determine what is providing.

What is dagger Singleton?

The @Singleton annotation is used to declare to Dagger that the provided object is to be only initialized only once during the entire lifecycle of the Component which uses that Module.


1 Answers

There's a simple/obvious workaround to achieve the same thing, depending on what the rest of your code looks like.

By not using field injection to initialize the mView field of the base presenter, you could just pass it into the constructor, and let the Module provide it, like:

public abstract class Presenter<T extends BaseView> {
    private final T mView;

    public Presenter(T view) {
        mView = view;
    }

    public void showLoadingIndicator() {
        mView.showLoading();
    }
}

assuming it's used like this:

public class MainPresenter extends Presenter<MainActivity> {
    public MainPresenter(MainActivity view) {
        super(view);
    }
}

and the module creates the presenter and passes the view to it:

@Module(injects = MainActivity.class)
public class MainModule {
    private final MainActivity mMainActivity;

    public MainModule(MainActivity mainActivity) {
        mMainActivity = mainActivity;
    }

    @Provides
    MainPresenter mainPresenter() {
        return new MainPresenter(mMainActivity);
    }
}

I prefer this anyway, because I prefer constructor injection over field injection (except on the objects not created by Dagger such as the activity or fragment level of course, where we can't avoid @Inject).

code here

like image 100
G. Lombard Avatar answered Sep 28 '22 08:09

G. Lombard