RxJava / Retrofit Call for every item in a reponse

I call my API with retrofit/rxJava and I get an Observable response like a Single List of BreedDog

. You can see my code :

compositeDisposable.add(breedDogsDisplayDataRepository.getBreedDogs(name)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeWith(new DisposableSingleObserver<List<BreedDog>>() {

                @Override
                public void onSuccess(List<BreedDog> breedDogList) {
                    Log.e("test", "okPresenter");
                    view.displayBreedDogs(breedDogToViewModelMapper.map(breedDogList));
                }

                @Override
                public void onError(Throwable e) {
                    Log.e("test", "errorPresenter : " + e.toString());
                    // handle the error case
                    System.out.println(e.toString());
                }
            }));

This works but now, for every items of this list I need to call my API to get an URL image and update my list.. But I don't know how... I tried change my Single response in Observable and used operator like flatMap or flatMapIterate.. etc But all time I got errors with the Object.. like no instance...etc

This is an example :

breedDogsDisplayDataRepository.getBreedDogs(name)
            .flatMapIterable(breedDogs -> breedDogs)
            .map( item ->   breedDogsDisplayDataRepository.getImageBreedDog(item.getId())
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribeWith(new DisposableSingleObserver<List<BreedImageResponse>>() {

                        @Override
                        public void onSuccess(List<BreedImageResponse> breedImageResponses) {

                        }

                        @Override
                        public void onError(Throwable e) {
                            Log.e("test", "errorPresenter : " + e.toString());
                            // handle the error case
                            System.out.println(e.toString());
                        }
                    })));

Do I use the good way ? Or need to change something ?

Upvotes: 0

Views: 214

Answers (2)

This is my solution to solve the problem :

public Single<List<BreedDogWithImage>> searchDogs(String name) {
    return getBreedDogs(name)
            .flatMapIterable(breedDogs -> breedDogs)
            .flatMap(breedDog -> getImageBreedDogs(breedDog.getId())
                    .flatMapIterable(breedDogWithImages -> breedDogWithImages))
            .toList();
}

And so I can call it like this :

public void searchBreedDogs(String name) {
    compositeDisposable.clear();
    compositeDisposable.add(breedDogsDisplayDataRepository.searchDogs(name)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeWith(new DisposableSingleObserver<List<BreedDogWithImage>>() {

                @Override
                public void onSuccess(List<BreedDogWithImage> breedDogWithImages) {
                    Log.e("test", "okCall" + breedDogWithImages);
                    view.displayBreedDogs(breedDogToViewModelMapper.map(breedDogWithImages));
                }

                @Override
                public void onError(Throwable e) {
                    Log.e("test", "error ");
                    e.printStackTrace();
                }
            }));
}

Upvotes: 0

Fred
Fred

Reputation: 17095

Without the signature of the repository it's hard to say exactly what's wrong, but you do mention that getBreedDogs returns a Single<List<BreedDogs>>. If this is the case, Single doesn't have a flatMapIterable as far as I know, but it has flattenAsObservable which can be used to do what you want I think.

It will map the list inside the single and emit its items as observables. This means you can no longer use map and have to switch to flatMap:

.flattenAsObservable(breedDogs -> breedDogs) 
.flatMapSingle(item -> breedDogsDisplayDataRepository.getImageBreedDog(item.getId()))

flatMapSingle is used because we're flat mapping Singles in this case

Another thing I noticed is that your "subscription part" is inside the map and you want this out of it. so ideally you'd move outside like:

.flattenAsObservable(breedDogs -> breedDogs) 
.flatMapSingle(item -> breedDogsDisplayDataRepository.getImageBreedDog(item.getId()))
.subscribeWith(/*...*/);

The schedulers is up to you. If you want your images to be downloaded in parallel I'd recommend to keep them inside the flatMapSingle.

Last thing, it seems that you want to receive a List<BreedImageResponse>, so I'd use toList(). Putting everything together:

breedDogsDisplayDataRepository.getBreedDogs(name)
  .flattenAsObservable(breedDogs -> breedDogs) 
  .flatMapSingle(item ->
    breedDogsDisplayDataRepository.getImageBreedDog(item.getId())
      .subscribeOn(Schedulers.io())
  )
  .toList()
  .observeOn(AndroidSchedulers.mainThread())
  .subscribeWith(new DisposableSingleObserver<List<BreedImageResponse>>() {
        @Override
        public void onSuccess(List<BreedImageResponse> breedImageResponses) { 
        }

        @Override
        public void onError(Throwable e) {}
  });

Upvotes: 0

Related Questions