如何在ReactiveX中正确组合计时器Observable?

时间:2015-07-07 16:01:16

标签: rx-java rx-android

方法startPositionInfoPolling从远程端执行PositionInfo的每2秒轮询并更新UI。

private Subscription mPollingTimerSubscription;
private Observable<Long> mPollingTimerObservable = Observable.timer(0, 2, TimeUnit.SECONDS);

private void startPositionInfoPolling() {
    LOGGER.trace("...");
    mPollingTimerSubscription = mPollingTimerObservable
            .flatMap(new Func1<Long, Observable<PositionInfo>>() {
                @Override
                public Observable<PositionInfo> call(Long ticker) {
                    LOGGER.debug("XXX ticker = {}", ticker);
                    return mMediaRendererClient.createPositionInfoObservable();
                }
            })
            .subscribeOn(AndroidSchedulers.mainThread())
            .subscribe(new Action1<PositionInfo>() {
                @Override
                public void call(final PositionInfo positionInfo) {
                    LOGGER.debug("XXX positionInfo = {}", positionInfo);
                    mMusicMediaTrackDetailsFragment.updateView(updatedPositionInfo);
                }
            });
}

方法stopPositionInfoPolling停止了UI更新。

private void stopPositionInfoPolling() {
    LOGGER.trace("...");
    mPollingTimerSubscription.unsubscribe();
}

我想更改代码,以便更少定期(例如每20秒)获取远程数据,并定期(例如每1秒)使用外推值更新UI。

我使用RxJava的第一个解决方案如下:

private Subscription mPollingTimerSubscription, mUpdatingTimerSubscription;
private Observable<Long> mPollingTimerObservable = Observable.timer(0, 20, TimeUnit.SECONDS);
private Observable<Long> mUpdatingTimerObservable = Observable.timer(0, 1, TimeUnit.SECONDS);

private void startPositionInfoPolling() {
    LOGGER.trace("...");
    mPollingTimerSubscription = mPollingTimerObservable
            .subscribe(new Action1<Long>() {
                @Override
                public void call(Long ticker) {
                    LOGGER.debug("XXX ticker = {}", ticker);
                    mMediaRendererClient.createPositionInfoObservable()
                            .retry(2)
                            .subscribe(new Action1<PositionInfo>() {
                                @Override
                                public void call(final PositionInfo positionInfo) {
                                    LOGGER.debug("XXX positionInfo = {}", positionInfo);
                                    mUpdatingTimerSubscription = mUpdatingTimerObservable
                                            .take(20, TimeUnit.SECONDS)
                                            .subscribeOn(AndroidSchedulers.mainThread())
                                            .subscribe(new Action1<Long>() {
                                                @Override
                                                public void call(Long ticker) {
                                                    LOGGER.debug("XXX ticker = {}", ticker);
                                                    String updatedRelTime = ModelUtil.toTimeString(ModelUtil.fromTimeString(positionInfo.getRelTime()) + ticker);
                                                    PositionInfo updatedPositionInfo = new PositionInfo(positionInfo, updatedRelTime, positionInfo.getAbsTime());
                                                    LOGGER.debug("XXX positionInfo = {}", updatedPositionInfo);
                                                    mMusicMediaTrackDetailsFragment.updateView(updatedPositionInfo);
                                                }
                                            });
                                }
                            });
                }
            });
}

private void stopPositionInfoPolling() {
    LOGGER.trace("...");
    mPollingTimerSubscription.unsubscribe();
    mUpdatingTimerSubscription.unsubscribe();
}

有人可以帮助我将这段代码转换成更少回调的东西吗?!我认为flatMap是关键,但我的思想仍然没有被动反应; - )

另一个问题是mPollingTimerSubscription.unsubscribe();没有取消订阅/取消/停止mUpdatingTimerObservable,因此正在维护另一个订阅。

提前感谢任何评论。

更新:感谢@hello_world减少原有的复杂性; - )

private Subscription mPollingTimerSubscription, mUpdatingTimerSubscription;
private Observable<Long> mPollingTimerObservable = Observable.timer(0, 20, TimeUnit.SECONDS);
private Observable<Long> mUpdatingTimerObservable = Observable.timer(0, 1, TimeUnit.SECONDS);

private void startPositionInfoPolling() {
    LOGGER.trace("...");
    mPollingTimerSubscription = mPollingTimerObservable
            .flatMap(new Func1<Long, Observable<PositionInfo>>() {
                @Override
                public Observable<PositionInfo> call(Long ticker) {
                    LOGGER.debug("XXX ticker = {}", ticker);
                    return mMediaRendererClient.createPositionInfoObservable();
                }
            })
            .retry(2)
            .subscribe(new Action1<PositionInfo>() {
                @Override
                public void call(final PositionInfo positionInfo) {
                    LOGGER.debug("XXX positionInfo = {}", positionInfo);
                    mUpdatingTimerSubscription = mUpdatingTimerObservable
                            .take(20, TimeUnit.SECONDS)
                            .subscribeOn(AndroidSchedulers.mainThread())
                            .subscribe(new Action1<Long>() {
                                @Override
                                public void call(Long ticker) {
                                    LOGGER.debug("XXX ticker = {}", ticker);
                                    String updatedRelTime = ModelUtil.toTimeString(ModelUtil.fromTimeString(positionInfo.getRelTime()) + ticker);
                                    PositionInfo updatedPositionInfo = new PositionInfo(positionInfo, updatedRelTime, positionInfo.getAbsTime());
                                    LOGGER.debug("XXX positionInfo = {}", updatedPositionInfo);
                                    mMusicMediaTrackDetailsFragment.updateView(updatedPositionInfo);
                                }
                            });
                }
            });
}

private void stopPositionInfoPolling() {
    LOGGER.trace("...");
    mPollingTimerSubscription.unsubscribe();
    mUpdatingTimerSubscription.unsubscribe();
}

1 个答案:

答案 0 :(得分:0)

经过与@hello_world的一些讨论和一些思考之后,两个带时间戳的观察者的组合观察似乎完成了这项工作。 确实非常强大的概念,但由于Java语法,它有点丑陋的代码。

private Subscription mPollingAndUpdatingTimerSubscription;
private Observable<Long> mPollingTimerObservable = Observable.timer(0, 20, TimeUnit.SECONDS);
private Observable<Long> mUpdatingTimerObservable = Observable.timer(0, 1, TimeUnit.SECONDS);

private void startPositionInfoPolling() {
    LOGGER.trace("...");
    Observable<Timestamped<PositionInfo>> timestampedPositionInfoObservable =
            mPollingTimerObservable
                    .flatMap(new Func1<Long, Observable<PositionInfo>>() {
                        @Override
                        public Observable<PositionInfo> call(Long ticker) {
                            LOGGER.debug("XXX ticker = {}", ticker);
                            return mMediaRendererClient.createPositionInfoObservable();
                        }
                    })
                    .retry()
                    .timestamp();
    Observable<Timestamped<Long>> timestampedUpdateObservable = mUpdatingTimerObservable.timestamp();
    Observable<PositionInfo> combinedPositionInfoObservable = Observable.combineLatest(
            timestampedPositionInfoObservable,
            timestampedUpdateObservable,
            new Func2<Timestamped<PositionInfo>, Timestamped<Long>, PositionInfo>() {
                @Override
                public PositionInfo call(Timestamped<PositionInfo> timestampedPositionInfo, Timestamped<Long> timestampedUpdate) {
                    PositionInfo orgPositionInfo = timestampedPositionInfo.getValue();
                    long delayInMillis = timestampedUpdate.getTimestampMillis() - timestampedPositionInfo.getTimestampMillis();
                    LOGGER.debug("XXX delayInMillis = {}", delayInMillis);
                    String updatedRelTime = DurationUtil.format(DurationUtil.parse(orgPositionInfo.getRelTime()).getTime() + delayInMillis);
                    return new PositionInfo(orgPositionInfo, updatedRelTime, orgPositionInfo.getAbsTime());
                }
            });
    mPollingAndUpdatingTimerSubscription =
            combinedPositionInfoObservable
                    .subscribeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Action1<PositionInfo>() {
                        @Override
                        public void call(final PositionInfo positionInfo) {
                            LOGGER.debug("XXX positionInfo = {}", positionInfo);
                            mMusicMediaTrackDetailsFragment.updateView(positionInfo);
                        }
                    });
}

private void stopPositionInfoPolling() {
    LOGGER.trace("...");
    mPollingAndUpdatingTimerSubscription.unsubscribe();
}