具有Backpressure的RxJava主题 - 只有在下游完成消耗后才允许最后一个值发出

时间:2017-01-31 13:07:24

标签: android rx-java2

我有一个PublishSubject在某个UI事件上调用onNext()。订户通常需要2秒钟才能完成其工作。在订户忙时,我需要忽略除{1}之外的所有呼叫,但最后一次呼叫除外。我尝试了以下方法,但是我无法控制流量。请求似乎排队等待,每个请求都得到处理(因此背压似乎不起作用)。如何让它忽略所有请求,但最后一个? (我不想使用onNext(),因为代码需要立即做出反应,任何合理的小超时都不会起作用。

此外,我意识到使用debounce主题没有效果,因此我使用subscribeOn在其中一个运算符中执行异步工作。这是正确的方法吗?

observeOn

我看到的输出是:

Subject<Boolean> loadingQueue = PublishSubject.<Boolean>create().toSerialized();

loadingQueue
  .toFlowable(BackpressureStrategy.LATEST)
  .observeOn(AndroidSchedulers.mainThread())
  .map(discarded -> {
    // PRE-LOADING
    Log.d("RXLOADING", "PRE-LOADING: " + Thread.currentThread().getName());
    return discarded;
   })
   .observeOn(Schedulers.computation())
   .map(b -> {
     Log.d("RXLOADING", "LOADING: " + Thread.currentThread().getName());
     Thread.sleep(2000);
     return b;
   })
   .observeOn(AndroidSchedulers.mainThread())
   .subscribe(b -> {
      Log.d("RXLOADING", "FINISHED: " + Thread.currentThread().getName() + "\n\n");
   });


loadingQueue.onNext(true);
loadingQueue.onNext(true);
loadingQueue.onNext(true);
....

相反,我希望代码执行以下操作(即加载一次,并且在加载时,背压以阻止所有请求并在第一个观察者完成后发出最后一个请求 - 所以总理想它最多只能加载两次):

PRE-LOADING: main
PRE-LOADING: main
LOADING: RxComputationThreadPool-1
PRE-LOADING: main
PRE-LOADING: main
PRE-LOADING: main
PRE-LOADING: main
PRE-LOADING: main
PRE-LOADING: main
LOADING: RxComputationThreadPool-1
FINISHED: main
LOADING: RxComputationThreadPool-1
FINISHED: main
LOADING: RxComputationThreadPool-1
FINISHED: main
LOADING: RxComputationThreadPool-1
FINISHED: main
LOADING: RxComputationThreadPool-1
FINISHED: main
LOADING: RxComputationThreadPool-1
FINISHED: main
LOADING: RxComputationThreadPool-1
FINISHED: main
FINISHED: main

1 个答案:

答案 0 :(得分:5)

你不能用observeOn执行此操作,因为它将缓冲至少1个元素,因此如果已经发生一次“加载”,则始终执行“PRE-LOADING”阶段。

但是您可以使用delay来执行此操作,因为它不会操纵链上的请求数量并在调度程序上单独调度每个onNext,而无需自行排队:

public static void main(String[] args) throws Exception {
    Subject<Boolean> loadingQueue = 
         PublishSubject.<Boolean>create().toSerialized();

    loadingQueue
      .toFlowable(BackpressureStrategy.LATEST)
      .delay(0, TimeUnit.MILLISECONDS, Schedulers.single())        // <-------
      .map(discarded -> {
        // PRE-LOADING
        System.out.println("PRE-LOADING: " 
             + Thread.currentThread().getName());
        return discarded;
       })
       .delay(0, TimeUnit.MILLISECONDS, Schedulers.computation())  // <-------
       .map(b -> {
           System.out.println("LOADING: " 
             + Thread.currentThread().getName());
         Thread.sleep(2000);
         return b;
       })
       .delay(0, TimeUnit.MILLISECONDS, Schedulers.single())       // <-------
       .rebatchRequests(1)             // <----------------------------------- one-by-one
       .subscribe(b -> {
           System.out.println("FINISHED: " 
               + Thread.currentThread().getName() + "\n\n");
       });


    loadingQueue.onNext(true);
    loadingQueue.onNext(true);
    loadingQueue.onNext(true);

    Thread.sleep(10000);
}