Android 带有背压的RxJava主题-仅在下游完成消费后才让最后一个值发出

Android 带有背压的RxJava主题-仅在下游完成消费后才让最后一个值发出,android,rx-java2,Android,Rx Java2,我有一个PublishSubject,它在某些UI事件上调用onNext()。订阅者通常需要2秒钟才能完成其工作。我需要忽略对onNext()的所有呼叫,但最后一个呼叫除外,因为用户正忙。我尝试了以下方法,但无法控制流量。请求似乎排队,每个请求都得到处理(因此背压似乎不起作用)。如何使其忽略除最后一个请求之外的所有请求?(我不想使用debounce,因为代码需要立即做出反应,任何合理的小超时都不起作用) 此外,我意识到对主题使用subscribeOn没有效果,因此我使用observeOn在其中一

我有一个PublishSubject,它在某些UI事件上调用
onNext()
。订阅者通常需要2秒钟才能完成其工作。我需要忽略对
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);
....
相反,我希望代码能够执行以下操作(即加载一次,并且在加载过程中,在第一个观察者完成后,施加反向压力以阻止所有请求并发出最后一个请求,因此总体而言,理想情况下,它最多只能加载两次):


您不能使用
observeOn
执行此操作,因为它将缓冲至少1个元素,因此如果已经有一个“加载”发生,则始终执行“预加载”阶段

但是,您可以使用
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);
}
publicstaticvoidmain(字符串[]args)引发异常{
主题加载队列=
PublishSubject.create().toSerialized();
加载队列
.toFlowable(背压等级最新)
.delay(0,TimeUnit.ms,Schedulers.single())//{
//预加载
System.out.println(“预加载:
+Thread.currentThread().getName());
退货报废;
})
.delay(0,TimeUnit.ms,Schedulers.computation())//{
System.out.println(“加载:”
+Thread.currentThread().getName());
《睡眠》(2000年);
返回b;
})

.delay(0,TimeUnit.ms,Schedulers.single())//非常感谢。我必须承认,我从来没有想到过这一点。我现在必须更详细地研究延迟和重新安排任务。@akarnokd我很好奇,我发现用
observeOn(Schedulers.single(),false,1)替换原始代码中的第一个
observeOn
会导致相同的行为-这是一个有效的替代解决方案,还是这样做会有一些负面影响?谢谢!如果项目可以区分,那么是的;它将存储项目2,而最新的项目将向前运行到项目N。当处理结束时,一个新的请求将处理项目2,然后第一个观察将继续store item#N.您将无法获得最新的时间快照。@akarnokd请帮助我获得相同的快照,但不要获取最后一个事件,我希望所有在订阅服务器忙于之前的事件/事件(如果是单个事件)时发生的事件,只需使用
BackpressureStragy.BUFFER
PRE-LOADING: main
LOADING: RxComputationThreadPool-1
FINISHED: main

PRE-LOADING: main
LOADING: RxComputationThreadPool-1
FINISHED: main
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);
}