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