RxJava + retrofit, get a List and add extra info for each item

一世执手 提交于 2019-12-03 16:04:10

Finally I found a nice way to do it.

private void startPolling() {
    pollDeliveries = Observable.interval(POLLING_INTERVAL, TimeUnit.SECONDS, Schedulers.from(AsyncTask.THREAD_POOL_EXECUTOR))
            .flatMap(tick -> getDeliveriesObs())
            .doOnError(err -> Log.e("MPB", "Error retrieving messages" + err))
            .retry()
            .subscribe(this::parseDeliveries, Throwable::printStackTrace);
}

private Observable<List<Delivery>> getDeliveriesObs() {
    return RestClient.getInstance().getApiService().getDeliveries()
            .flatMap(Observable::from)
            .flatMap(this::getETAForDelivery)
            .toSortedList((d1, d2) -> {
                if (d1.getEta() == null) {
                    return -1;
                }
                if (d2.getEta() == null) {
                    return 1;
                }
                return d1.getEta().getDuration().getValue() > d2.getEta().getDuration().getValue() ? 1 : -1;
            });
}

Let's go step by step.

  1. First we create an Observable that triggers every POLLING_INTERVAL time the method getDeliveriesObs() that will return the final list
  2. We use retrofit to get an Observable of the call
  3. We use flatMap to flattern the resut list and get in the next flatmap a Delivery item, one by one.
  4. Then we get the estimated time of arrival set inside the Delivery object and return it
  5. We sort the list to order by estimated time of arrival.
  6. In case of error we print and retry so the interval does not stop
  7. We subscribe finally to get the list sorted and with ETA inside, then we just return it or whatever you need to do with it.

It's working properly and it's quite nice, I'm starting to like rxjava :)

I haven't spent a lot of time with Java 8 lambdas, but here's an example of mapping each object to a different object, then getting a List<...> out at the other end in plain ol' Java 7:

List<Delivery> deliveries = ...;
Observable.from(deliveries).flatMap(new Func1<Delivery, Observable<ETA>>() {
    @Override
    public Observable<ETA> call(Delivery delivery) {
        // Convert delivery to ETA...
        return someEta;
    }
})
.toList().subscribe(new Action1<List<ETA>>() {
    @Override
    public void call(List<ETA> etas) {

    }
});

Of course, it'd be nice to take the Retrofit response (presumably an Observable<List<Delivery>>?) and just observe each of those. For that we ideally use something like flatten(), which doesn't appear to be coming to RxJava anytime soon.

To do that, you can instead do something like this (much nicer with lambdas). You'd replace Observable.from(deliveries) in the above example with the following:

apiService.getDeliveries().flatMap(new Func1<List<Delivery>, Observable<Delivery>>() {
    @Override
    public Observable<Delivery> call(List<Delivery> deliveries) {
        return Observable.from(deliveries);
    }
}).flatMap(...)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!