Search code examples
androidretrofit2rx-androidandroid-mvp

Modify callbacks with RxAndroid MVP Retrofit


I have been using MVP architecture with Retrofit with callbacks for some time. I would like to replace my callbacks with RxJava/Android but I can't seem to grasp on how it should be done.

I have an interface for the Interceptor(Interactor):

    public interface FoodInterceptor extends MvpInterceptor {
    /*void getFoodList(RestCallback<FoodListResponse> callback);*/

    Observable getFoodList(Consumer<FoodListResponse> foodListResponseConsumer, Consumer<Throwable> error);
}

And then the interceptor implementation:

    public class FoodInterceptorImpl implements FoodInterceptor {

    @Inject
    ApiService mApiService;
    @Inject
    ErrorUtils mErrorUtils;
    @Inject
    SchedulerProvider mSchedulerProvider;
    @Inject
    CompositeDisposable mCompositeDisposable;

    @Inject
    public FoodInterceptorImpl() {
        super();
    }

    @Override
public Observable<FoodListResponse> getFoodList(Consumer<FoodListResponse> foodListResponseConsumer, Consumer<Throwable> throwable) {
    mApiService.getFoodList()
            .subscribeOn(mSchedulerProvider.backgroundThread())
            .observeOn(mSchedulerProvider.mainThread())
            .subscribe(foodListResponse -> Log.d("TAG", "FoodResponse: " + foodListResponse),
                    throwable1 -> Log.d("TAG", "Throwable: " + throwable));

    return ?;
}

    @Override
    public void unbind() {

    }

    /*@Override
    public void getFoodList(final RestCallback<FoodListResponse> callback) {
        mApiService.getFoodList().enqueue(new Callback<FoodListResponse>() {
            @Override
            public void onResponse(Call<FoodListResponse> call, Response<FoodListResponse> response) {
                if (response.isSuccessful()) {
                    Result<FoodListResponse> result = new Result<>();
                    FoodListResponse foodListResponse = response.body();
                    result.setData(foodListResponse);
                    callback.onSuccess(result);
                } else {
                    mRestError = mErrorUtils.parseResponse(response);
                    Log.d("Test", "Error: " + mRestError.getMessage());
                }

            }

            @Override
            public void onFailure(Call<FoodListResponse> call, Throwable t) {

            }
        });

    }*/

    /*@Override
    public void cleanup() {

    }*/

}

In the commented code you can see how I would do it with a callback, but Rx required me to return Observable. How would I do that? And how do I inform my presenter that data has been fetched?

Presenter interface:

@PerActivity
public interface FoodPresenter<V extends FoodView, I extends FoodInterceptor> extends MvpPresenter<V, I> {
    void renderFoods();
}

And the Presenter:

    public class FoodPresenterImpl<V extends FoodView, I extends FoodInterceptor>
        extends BasePresenter<V, I> implements FoodPresenter<V, I> {

    @Inject
    public FoodPresenterImpl(I mvpInterceptor,
                             SchedulerProvider schedulerProvider,
                             CompositeDisposable compositeDisposable) {
        super(mvpInterceptor, schedulerProvider, compositeDisposable);
    }



 @Override
public void renderFoods() {
    getMvpView().showProgress(true);
    getInterceptor().getFoodList(foodListResponse -> {
        if (!isViewAttached()) {
            return;
        }
        getMvpView().renderFoods(foodListResponse.getFoodList().getFoodItemList());
        getMvpView().showProgress(false);
    }, throwable -> {
        if (!isViewAttached()) {
            return;
        }
        getMvpView().showProgress(false);
    });
}

    /*@Override
    public void renderFoods() {
        getMvpView().showProgress(true);
        getInterceptor().getFoodList(new RestCallback<FoodListResponse>() {
            @Override
            public void onSuccess(Result<FoodListResponse> result) {
                if (!isViewAttached()) {
                    return;
                }
                getMvpView().renderFoods(result.getData().getFoodList().getFoodItemList());
                getMvpView().showProgress(false);
            }

            @Override
            public void onFailure(RestError error) {

            }
        });
    }*/
}

Solution

  • Let me decompose you logic a bit:

    1. renderFoods get called in presenter
    2. Presenter call intercepter, so it will fetch api and return result
    3. Interceptor call mApi.getFoodList() (it should return Observable) and itnterceptro subscribes to result. I will use lambda, so there can be missed parts:

      mApi.getFoodList()
        .subscribeOn(Schedulers.io()) // main work will be on io thread
        .observeOn(AndroidSchedulers.mainThread()) // result will be passed to main thread
        .subscribe((result, throwable) -> {
           // it's like your calback, the job are done 
           // and you get result in result parameter, 
           // and if error occurs, result will be null 
           // and throwable parameter has an cause
           // so, here you can apply errorUtils on result, check the throwable, 
           // or pass result to your presenter
        });
      

    Hope it helps!