从可观察到第一次订阅的缓存项目以处理竞争状况

时间:2019-01-17 16:35:09

标签: android kotlin reactive-programming rx-java2

我正在使用Reactive Extensions(RxJava 2)对蓝牙设备执行RPC调用,从而导致传入的数据流,我随后对其进行了解析,还使用了Rx。生成的API是简单的Flowable<DownloadedRecord>。为此,我正在Rx API of the Sweetblue library for Android之上构建。

我的问题是,在“请求”设备开始流传输与及时订阅流以确保没有任何数据包丢失之间存在竞争状态。

我使用Completable首先执行RPC调用以请求数据流开始andThen( readRecords )。在readRecords有时间订阅此流之前,Sweetblue发出了一些数据包,从而“中断” readRecords

要摆脱这种具体情况,请采用以下独立代码:

val numbers = PublishSubject.create<Int>()

var currentTotal = 0
val sumToTen = numbers
    .doOnNext { currentTotal += it }
    .doOnNext { println( "Produced $it" ) }
    .takeUntil { currentTotal >= 10 }
    .doOnComplete { println( "Produced a total of $currentTotal." ) }

Completable.fromAction { numbers.onNext( 9 ) } ) // Mimic race condition.
    .andThen( sumToTen )
    .subscribe { println( "Observed: $it, Current total: $currentTotal" ) }

numbers.onNext( 1 )

numbers.onNext( 9 )调用模仿了竞争条件。 sumToTen从未观察到此数字,因为sumToTen仅在下一行订阅。因此,流永远不会完成。

经过一番调查,我了解我可以使用replayconnect'解决'这个问题。

val numbers = PublishSubject.create<Int>()

var currentTotal = 0
val sumToTen = numbers
    .doOnNext { currentTotal += it }
    .doOnNext { println( "Produced $it" ) }
    .takeUntil { currentTotal >= 10 }
    .doOnComplete { println( "Produced a total of $currentTotal." ) }
    .replay( 1 ) // Always replay last item upon subscription.

Completable.fromAction { sumToTen.connect() }
    .andThen( Completable.fromAction { numbers.onNext( 9 ) } )
    .andThen( sumToTen )
    .subscribe { println( "Observed: $it, Current total: $currentTotal" ) }

numbers.onNext( 1 )

现在sumToTen流完成了,因为通过在“开始流数据”(sumToThen)之前首先连接到onNext( 9 ),该流订阅了numbers,因此会发生预期的副作用(currentTotal)。 但是,仅当replay缓冲区足够大(在这种情况下为)时,才会观察到'9'。例如,将replay( 1 )替换为publish将使流完成(“总共产生10个”),但不会观察到“ 9”。

我对这种解决方案不完全满意,原因有两个:

  1. 这只是最大限度地减少了发生竞争状况的机会。设置replay缓冲区的大小是任意的。
  2. 这将始终将replay中指定数量的元素保留在内存中,即使目的是直到订阅为止。

实际上,这两个都不是真正的问题,但是从可维护性的角度来看这是一个大问题:代码没有清楚地传达意图

是否有更好的方法来应对这种情况?例如:

  • 一个replay运算符,只为一个订户重播(因此,一旦第一次发出,就删除缓存)。
  • 与我在publish/connect上探索的方法完全不同吗?

0 个答案:

没有答案