【问题标题】:RxJava/Android monitor progress of multiple subscribers fired at different timesRxJava/Android 监控在不同时间触发的多个订阅者的进度
【发布时间】:2016-02-08 05:21:20
【问题描述】:

我正在寻找一种方法,希望使用 RxJava 来保持一致性,以监控可能在不同时间触发的多个订阅者的进度。我知道当订阅者全部从一种方法触发时如何将它们合并或 flatMap 订阅者在一起,但我不知道当它们在不同时间从不同方法触发时如何做到这一点。

例如,如果我有 2 个长时间运行的任务附加到按钮按下。我按下按钮 1 并触发 observable/subscriber,在运行的中途我按下按钮 2 来触发第二个 observable/subscriber。

我想在没有任务运行时启用一个按钮,并在一个或多个任务运行时禁用它。

这可能吗?我也在尽量避免设置实例变量标志。

【问题讨论】:

  • 在您的示例中,您将首先在同一个位置订阅两个按钮,并可能使用combineLatest 之类的东西从它们那里获取事件

标签: android rx-java rx-android


【解决方案1】:

我会使用单独的BehaviorSubjectscan 来监控执行状态。这与实例变量非常相似,但它可能会启发您找到更好的解决方案。像这样的:

private final BehaviorSubject<Integer> mProgressSubject = BehaviorSubject.create(0);

public  Observable<String> firstLongRunningOperations() {
    return Observable.just("First")
            .doOnSubscribe(() -> mProgressSubject.onNext(1))
            .finallyDo(() -> mProgressSubject.onNext(-1)));
}

public  Observable<String> secondLongRunningOperations() {
    return Observable.just("Second")
            .doOnSubscribe(() -> mProgressSubject.onNext(1))
            .finallyDo(() -> mProgressSubject.onNext(-1));
}

public Observable<Boolean> isOperationInProgress() {
    return mProgressSubject.asObservable()
            .scan((sum, item) -> sum + item)
            .map(sum -> sum > 0);
}

用法如下:

isOperationInProgress()
        .subscribe(inProgress -> {
            if (inProgress) {
                //disable controls
            } else {
                //enable controls
            }
        });

使用这种方法,您可以进行任意数量的长时间运行操作,而不必全部触发。只是不要忘记致电doOnSubscribefinallyDo

PS。抱歉,我没有测试它,但它应该可以工作。

【讨论】:

  • 将实现包装到自己的类中,效果很好。谢谢!
  • 什么是 BehaviorSubject?
【解决方案2】:

为了实现这一点,让两个长时间运行的操作在 PublishSubject 上发出 onNext 事件。将两个主题与 zip 或 combineLatest 函数结合起来并订阅它。一旦 combine 函数接收到一个事件,这意味着两个 Subjects 都发出了 onNext 事件,因此两个长时间运行的操作都已完成,您可以启用第三个按钮。

private PublishSubject<Boolean> firstSubject = PublishSubject.create();
private PublishSubject<Boolean> secondSubject = PublishSubject.create();

@Override
public void onStart() {
    super.onStart();
    subscribeToResult();
}

private Observable<Integer> firstOperation() { 
    return Observable.just(100)
                .delay(1000) // takes a while
                .subscribe(tick -> firstSubject.onNext(true));
}

private Observable<Integer> firstOperation() { 
    return Observable.just(200)
                .delay(1000) // takes a while
                .subscribe(tick -> secondSubject.onNext(true));
}

private void subscribeToResult() {
    Observable.zip(
        firstSubject,
        secondSubject,
        (firstResult, secondResult) -> return true
    ).subscribe(
        tick -> thirdButton.setEnabled(true)
    )
}

一定要看看 RxJava 的组合函数。

【讨论】:

  • 我喜欢这个主意。如果第二个按钮从未被按下,它是否仍然有效?
  • zip 只有在所有封闭的 Observable 都发出了一个项目时才会发出, combineLatest 也只会在每个 observable 至少发出一个值后发出所有 Observable 的最新值。因此,在您的情况下,只有在两个长操作完成后才会启用第三个按钮。
  • 我需要处理按钮 2 从未被按下的情况。基本上,我希望在没有任务运行时启用该按钮,并在任务运行时禁用该按钮。我应该在最初的问题中更清楚地说明这一点,现在将对其进行编辑。
猜你喜欢
  • 1970-01-01
  • 2020-10-08
  • 2017-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-15
相关资源
最近更新 更多