6
votes

I want to build an Android app using the MVP pattern.

I have a fragment (the view) and a presenter class.

What I want is to basically inject the presenter into the fragment, and set the fragment as the presenter's view (via an interface that the view will implement)

How can I easily and correctly connect the 2 using dependency injection (with Dagger2)?

Edit:

In addition, I'd like the presenter to be a singleton, so it will be able to persist data & state across orientation changes

2
Have you considered Mortar github.com/square/mortar ? or nucleus github.com/konmik/nucleus ? - Emma
Thanks @Emma, those libs look interesting. However, I'm trying to learn about using dagger2 and DI, and so I would still like to know what is a good way to implement MVP using Dagger2 - dors
I see. Mortar uses dagger as view injection however mortar has its own view and presenter classes so you will not use fragment, though. - Emma
Thanks :) I would still like to know the answer to my question using dagger2 though - dors
If you want to bind a presenter to the scope of the activity or the fragment, then you'll need either the scopes provided by Mortar, or you'll need a retained fragment, or you'll need singleton presenters which are a pain to get right. Dagger2 and orientation-surviving-scopes are not mutually exclusive, in fact, they are quite orthogonal. Mortar allows the retaining of the subscoped component with minimal hassle. - EpicPandaForce

2 Answers

3
votes

First you need to define a presenter module:

@Module
class SearchPresenterModule {
    @NonNull
    private final SearchContract.View mView;

    SearchPresenterModule(@NonNull SearchContract.View view) {
        this.mView = view;
    }

    @Provides
    SearchContract.View provideSearchContractView() {
        return mView;
    }
}

Here's the example component:

@FragmentScoped
@Component(modules = SearchPresenterModule.class)
interface SearchComponent {
    void inject(SearchActivity activity);
}

And inject your presenter:

@Inject
SearchPresenter mSearchPresenter;

DaggerSearchComponent.builder()
            .searchPresenterModule(new SearchPresenterModule(searchFragment))
            .build()
            .inject(this);

Finally inject your presenter's constructor:

 @Inject
 SearchPresenter(@NonNull SearchContract.View view, @NonNull SearchRepository searchRepository) {
        this.mView = view;

        mView.setPresenter(this);
    }

Extra: Here's fragmentscoped annotation:

@Documented
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface FragmentScoped {

}

You can check my example repo for MVP + DAGGER2 https://github.com/savepopulation/wikilight

0
votes

so the presenter is like

@Singleton
public class Presenter{
private View mView; ...

the view should be

public class View extends ...{
    @Inject
    protected Presenter mPresenter ...

Well, you just need a method in your module like

inject(View view)

and Dagger should take care of the rest like the singleton instance and the injection