Search code examples
androidrx-javarx-java2android-mvp

RxJava thread not waiting for result


I have this method that I am trying to pull data from an API, and then update the text view. Everything works except getRecipeName doesn't finish after the "end Method" log. .getRecipeName() uses RetroFit to pull from an API.

I am currently learning MVP, Dagger, RxJava, and Butterknife all at once using Mindork's Github page on MVP Architecture

I commented out the .subscribeOn and .observeOn to see the result difference and nothing changed.

@Override
public void onRandomButtonClicked() {

    getMvpView().showLoading();
    Log.e(TAG, "Random Method Open");
    getCompositeDisposable().add(getDataManager()
            .getRecipeName()
            //.subscribeOn(getSchedulerProvider().io())
            //.observeOn(getSchedulerProvider().ui())
            .subscribe(new Consumer<String>() {
                @Override
                public void accept(String s) throws Exception {
                    Log.e(TAG, "accept");
                    getMvpView().updateTextView(title);
                }
            }));

    Log.e(TAG, "end method");

}

Here is my getRecipeName() method

@Override
public Observable<String> getRecipeName() {

    /*Create handle for the RetrofitInstance interface*/
    GetDataService service = RetrofitClientInstance.getRetrofitInstance().create(GetDataService.class);
    Call<RecipeList> call = service.getRecipe();
    call.enqueue(new Callback<RecipeList>() {
        @Override
        public void onResponse(@NonNull Call<RecipeList> call, @NonNull retrofit2.Response<RecipeList> response) {


            Log.e("onResponse","Recipe is Successful = " + response.isSuccessful());
            //if response is false then skip to avoid null object reference
            if (response.isSuccessful()) {

                RecipeList drinkRecipe = response.body();

                List<Recipe> recipes = drinkRecipe.getDrinks();
                jokeText = String.valueOf(recipes.size());
                Recipe myRecipe = recipes.get(0);
                jokeText = myRecipe.getStrDrink();

                Log.e("On Response", "Result2: " + jokeText);
            }
            //jokeText = "null";

        }

        @Override
        public void onFailure(Call<RecipeList> call, Throwable t) {
            Log.e("On Response","Failure");
        }
    });

    //return jokeText;
    return Observable.fromCallable(new Callable<String>() {
        @Override
        public String call() throws Exception {
            return jokeText;
        }
    });
}

Solution

So as the comments stated RxJava Adapter was the correct way to go. I will just post my working code on myself using the adapter. I found it very difficult to find a working example.

//single api call using retrofit and rxjava
@SuppressLint("CheckResult")
private void getRandomButtonClick(){

    retrofit = RetrofitClientInstance.getRetrofitInstance();

    retrofit.create(GetDataService.class).getRecipe()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(this::handleResults, this::handleError );
}

private void handleResults(RecipeList recipeList) {
    int i = recipeList.getDrinks().size();
    Log.e(TAG, "size is: "+ i);
    Recipe recipe = recipeList.getDrinks().get(0);
    getMvpView().updateTextView(recipe.getStrDrink());
}

 private void handleError(Throwable t){
    Log.e("Observer", "");

}

My Retrofit Client Instance

 public static Retrofit getRetrofitInstance() {
    if (retrofit == null) {
        retrofit = new retrofit2.Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
    }
    return retrofit;
}

My Interface

public interface GetDataService {

//@Headers({})
@GET("random.php")
Observable<RecipeList> getRecipe();

I found a great resource to reference for me to correctly implement this. Retrofit Android


Solution

  • The reason is because your observable is returning jokeText every time it is subscribed upon. It returns immediately after invocation and will not wait for your network operation.

    One possible solution is to use the RxJavaCallAdapter. Link here: https://github.com/square/retrofit/tree/master/retrofit-adapters/rxjava2

    It will automatically convert your API returns to observables. No need to manually invoke retrofit requests. Just process the response and convert it to your desired object from there.

    Another approach would be to wrap your entire sequence in an Observable.create or Observable.fromAsync.