web-dev-qa-db-fra.com

Comment attendre que async Observable se termine

J'essaye de construire un exemple en utilisant rxjava. L'exemple doit orchestrer un ReactiveWareService et un ReactiveReviewService revalorisant un composite WareAndReview.

ReactiveWareService
        public Observable<Ware> findWares() {
        return Observable.from(wareService.findWares());
    }

ReactiveReviewService: reviewService.findReviewsByItem does a ThreadSleep to simulate a latency!

public Observable<Review> findReviewsByItem(final String item) {
return Observable.create((Observable.OnSubscribe<Review>) observer -> executor.execute(() -> {
    try {
        List<Review> reviews = reviewService.findReviewsByItem(item);
        reviews.forEach(observer::onNext);
        observer.onCompleted();
    } catch (Exception e) {
        observer.onError(e);
    }
}));
}

public List<WareAndReview> findWaresWithReviews() throws RuntimeException {
final List<WareAndReview> wareAndReviews = new ArrayList<>();

wareService.findWares()
    .map(WareAndReview::new)
.subscribe(wr -> {
        wareAndReviews.add(wr);
        //Async!!!!
        reviewService.findReviewsByItem(wr.getWare().getItem())
            .subscribe(wr::addReview,
                throwable -> System.out.println("Error while trying to find reviews for " + wr)
            );
    }
);

//TODO: There should be a better way to wait for async reviewService.findReviewsByItem completion!
try {
    Thread.sleep(3000);
} catch (InterruptedException e) {}

return wareAndReviews;
}

Étant donné que je ne veux pas retourner un observable, comment puis-je attendre que l'async observable (findReviewsByItem) se termine?

12
user3753094

La plupart de votre exemple peut être réécrit avec des opérateurs RxJava standard qui fonctionnent bien ensemble:

public class Example {

    Scheduler scheduler = Schedulers.from(executor);

    public Observable<Review> findReviewsByItem(final String item) {
        return Observable.just(item)
               .subscribeOn(scheduler)
               .flatMapIterable(reviewService::findReviewsByItem);
    }
    public List<WareAndReview> findWaresWithReviews() {
        return wareService
               .findWares()
               .map(WareAndReview::new)
               .flatMap(wr -> {
                   return reviewService
                          .findReviewsByItem(wr.getWare().getItem())
                          .doOnNext(wr::addReview)
                          .lastOrDefault(null)
                          .map(v -> wr);
               })
               .toList()
               .toBlocking()
               .first();
    }
}

Chaque fois que vous souhaitez composer des services comme celui-ci, pensez d'abord à flatMap. Vous n'avez pas besoin de bloquer pour chaque sous-observable mais seulement à la toute fin avec toBlocking() si vraiment nécessaire.

17
akarnokd

Vous pouvez utiliser des méthodes de BlockingObservable voir https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators . par exemple

BlockingObservable.from(reviewService.findReviewsByItem(..)).toIterable()
12
Marek Hawrylczak