Search code examples
androiddependency-injectionmvpdagger-2

Trying to implement MVP using Dagger 2 - How can I get a reference to the Activity in the provided presenter


I am trying to set up an app with MVP and Dagger,

The view is an Activity which implements a view interface.

public class OverviewActivity extends AppCompatActivity implements OverviewContract.View {

    @Inject OverviewPresenter presenter;

    @BindView(R.id.history_days) ListView HistoryLabels;
    @BindView(R.id.history_events) ListView HistoryEvents;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_overview);
        ButterKnife.bind(this);

        DaggerOverviewComponent.create().inject(this);

    }

    @Override
    public void showHistory(List<Exercise> history) {
      // ...
    }

    @Override
    public void updateScoreSlider(float value) {
      // ...
    }

    @OnClick(R.id.add_event_button)
    public void addEvent(View v){
      // ...
    }
}

The presenter looks like so

public class OverviewPresenter implements OverviewContract.Events {

    OverviewContract.View view;

    public OverviewPresenter( OverviewContract.View overviewView ) {
        view = overviewView;

    }

    @Override
    public void loadHistory() {
        // TODO
    }

    @Override
    public void addNewEvent() {
        // TODO
    }
}

Where I am having trouble is with the provider for the presenter. One of the dependencies of OverviewPresenter is the OverviewActivity, but how am I supposed to inject the instance of OverviewActivity into the OverviewPresenter ?

@Module
public class PresenterModule {

    @Provides
    static OverviewPresenter provideOverviewPresenter(){
        return new OverviewPresenter(/* pass in the instance of the activity here?? */);
    }
}

My component looks like

@Component(modules = {PresenterModule.class})
public interface OverviewComponent {

    void inject(OverviewActivity overviewActivity);
}

Forgive me if this is way off base, I am still trying to wrap my head around dagger.

TLDR:
How can I set this up so that my OverviewActivity can be injected with an OverviewPresenter which itself is injected with the instance of OverviewActivity?


Solution

    • To provide things that dagger can not create itself, you need to use a module.
    • To provide your presenter, of which you can just annotate the constructor with @Inject you don't need to use a module—and shouldn't.

    Since your view implements the view, you can not create the view yourself, nor can dagger. Hence create a module to provide the view

    @Module
    public class OverviewModule {
    
        OverviewView mView;
    
        OverviewModule(OverviewView view) {
            mView = view;
        }
    
        @Provides
        static OverviewView provideOverviewView() {
            return mView;
        }
    }
    

    Then adapt your presenter to use constructor injection

    public class OverviewPresenter implements OverviewContract.Events {
    
        OverviewContract.View view;
    
        @Inject
        public OverviewPresenter( OverviewContract.View overviewView ) {
            view = overviewView;
        }
    }
    

    Then just add the module to your component and you're done.

    @Component(modules = {OverviewModule.class})
    public interface OverviewComponent {
    
        void inject(OverviewActivity overviewActivity);
    }
    

    Now just inject your presenter and you're done (something like this, there could be a typo):

    DaggerOverviewComponent.builder().overviewModule(new OverviewModule(this)).build()
            .inject(this);