Raffu Raffu - 1 month ago 25
Android Question

Dagger2: inject Api Module to presenter (MVP)

i'd like to ask about the way MVP and dagger working. So, in android development, we know that Activity and fragment is a view, and we make presenter by implementing observer (in my case, im using rxjava + retrofit). And the dagger in this case I use to inject Rest service (Network Component -> retrofit).

I still confuse to inject Rest service to my presenter, because all the example I found is injecting to activity.

here is my code.

As view :

public class PageFragment extends Fragment implements ScheduleViewInterface{
private ScheduleCursorAdapter scheduleAdapter;
@Inject RestApi restApiInject;
private SchedulePresenter mPresenterJson;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

App.getApiComponent(getActivity()).inject(this);
mPresenterJson.fetchSchedule();
}

@Override
public Observable<ScheduleList> getSchedule() {
return restApiInject.getScheduleListByUrl("url here");
}


As presenter :

public class SchedulePresenter implements Observer<ScheduleList> {
private ScheduleViewInterface mInterface;

public SchedulePresenter(ScheduleViewInterface viewInterface){
mInterface = viewInterface;
}

@Override
public void onCompleted() {
mInterface.jsonCompleted();
}

@Override
public void onError(Throwable e) {
mInterface.jsonError(e.getMessage());
}

@Override
public void onNext(ScheduleList scheduleList) {
mInterface.jsonScheduleList(scheduleList);
}

public void fetchSchedules(){
unSubscribeAll();
subscribe(mInterface.getSchedule(), SchedulePresenter.this);
}


and this is my dagger2 code

@CustomScope
@Component(modules = ApiModule.class, dependencies = NetworkComponent.class)
public interface ApiComponent {
MainActivity inject(MainActivity activity);
PageFragment inject(PageFragment fragment);
}


Architecture pattern

Answer

best practice is to create a Interactor class to handle this, and then inject that interactor in the presenter. look at my code in my project below to understand. the presenter code is :

public class PopularMoviesPresenterImpl implements PopularMoviesPresenter {

@Inject
public PopularMoviesInteractor interactor;

private PopularMoviesView view;
private Subscription subscription = Subscriptions.empty();

@Inject
public PopularMoviesPresenterImpl() {
}

@Override
public void setView(PopularMoviesView view) {
    this.view = view;
}

@Override
public void destroy() {
    if (subscription != null && !subscription.isUnsubscribed())
        subscription.unsubscribe();

    interactor.onDestroy();

    view = null;
    interactor = null;
}

@Override
public void loadPopularMoviesData(boolean isConnected, int page, int limit) {

    if (null != view) {
        view.showProgress();
    }

    subscription = interactor.loadPopularMovies(page, limit).subscribe(movies ->
            {
                if (null != view) {
                    view.hideProgress();
                    view.setPopularMoviesValue(movies);

                    if (!isConnected)
                        view.showOfflineMessage();
                }
            },
            throwable -> {
                if (null != view) {
                    view.hideProgress();
                }

                if (isConnected) {
                    if (null != view) {
                        view.showRetryMessage();
                    }
                } else {
                    if (null != view) {
                        view.showOfflineMessage();
                    }
                }
            });

}}

the interactor is:

public class PopularMoviesInteractorImpl implements PopularMoviesInteractor {
private TraktApi api;
private SchedulerProvider scheduler;

private ReplaySubject<Movie[]> moviesDataSubject;
private Subscription moviesSubscription;

@Inject
public PopularMoviesInteractorImpl(TraktApi api, SchedulerProvider scheduler) {
    this.api = api;
    this.scheduler = scheduler;
}

@Override
public Observable<Movie[]> loadPopularMovies(int page, int limit) {
    if (moviesSubscription == null || moviesSubscription.isUnsubscribed()) {
        moviesDataSubject = ReplaySubject.create();

        moviesSubscription = api.getPopularMovies(page, limit, Constants.API_EXTENDED_FULL_IMAGES)
                .subscribeOn(scheduler.backgroundThread())
                .observeOn(scheduler.mainThread())
                .subscribe(moviesDataSubject);
    }

    return moviesDataSubject.asObservable();
}

@Override
public void onDestroy() {
    if (moviesSubscription != null && !moviesSubscription.isUnsubscribed())
        moviesSubscription.unsubscribe();
}}

the interactor interface:

public interface PopularMoviesInteractor {

Observable<Movie[]> loadPopularMovies(int page, int limit);

void onDestroy();}

and in your module write:

 @Provides
public PopularMoviesInteractor provideInteractor(PopularMoviesInteractorImpl interactor) {
    return interactor;}

the interactor is provided through construction injection.(you can do it with simple injection though)

here is a clean example of the mvp: http://github.com/mmirhoseini/fyber_mobile_offers

Comments