RxJava - 将 delaySubscription 与 withLatestFrom 一起使用
RxJava - using delaySubscription with withLatestFrom together
很难解释我的问题,这就是为什么我会尝试用一个更简单的例子来解释。 (我也会在括号中包含我的案例,以明确为什么我需要解决这个问题)
val interval =
Observable.interval(1, TimeUnit.SECONDS)
val delayedRandomNumber =
Observable.fromCallable {
val randomNumber = Random().nextInt()
Log.d("LogTag", "random number = $randomNumber")
randomNumber
}.delay(5000, TimeUnit.MILLISECONDS)
interval
.observeOn(Schedulers.io())
.filter { it != 0L }
.delaySubscription<Int>(delayedRandomNumber)
.withLatestFrom(delayedRandomNumber, BiFunction<Long, Int, String> { second, randomNumber ->
"$randomNumber mod $second = ${randomNumber%second}"
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
Log.d("LogTag", it)
}
interval - 很明显,这每秒都会发出值(在我的例子中,它是从 EditText 发出的用户输入)
delayedRandomNumber - 这会生成一个随机数并在 5 秒后发出。我只需要生成一次但现在我不知道如何生成(在我的例子中它是来自服务器的 json 城市树)
delaySubscription - 我正在使用此运算符等待随机数。如果我不使用它,我将不会获得第二个值 1、2、3 的值(在我的例子中,我需要从第一个字母开始,因为它是基于树的数据——我有这样的约束)
withLatestFrom - 我使用这个运算符来避免每次都生成随机数(在我的例子中,我不想每次输入改变时都从服务器获取数据)
所以我需要同时使用delaySubscription和withLatestFrom。但是它通过生成随机数两次(在我的例子中加载数据两次)来制造问题
当我运行这段代码时,日志看起来是这样的:
random number = -1870536123
random number = -1834197628
-1870536123 mod 1 = 0
-1870536123 mod 2 = -1
-1870536123 mod 3 = 0
-1870536123 mod 4 = -3
-1870536123 mod 5 = -3
-1870536123 mod 6 = -3
如您所见,随机数生成了两次。
还有其他方法可以解决这个问题吗?如果是怎么办?
因为delayedRandomNumber
是cold observable或者单播。每个订阅都有自己的生产者(在您的情况下 Observable.fromCallable 内的随机数生成是生产者)。
为避免此问题,您可以使用 share 运算符多播 delayedRandomNumber
。
val delayedRandomNumber =
Observable.fromCallable {
val randomNumber = Random().nextInt()
Log.d("LogTag", "random number = $randomNumber")
randomNumber
}.delay(5000, TimeUnit.MILLISECONDS)
.share()
输出
random number = -942235082
result=-942235082
-942235082 mod 1 = 0
result=-942235082
-942235082 mod 2 = 0
result=-942235082
-942235082 mod 3 = -2
也请阅读 blog by Dan Lew,因为我发现它在遇到多播可观察对象问题时很有帮助。
很难解释我的问题,这就是为什么我会尝试用一个更简单的例子来解释。 (我也会在括号中包含我的案例,以明确为什么我需要解决这个问题)
val interval =
Observable.interval(1, TimeUnit.SECONDS)
val delayedRandomNumber =
Observable.fromCallable {
val randomNumber = Random().nextInt()
Log.d("LogTag", "random number = $randomNumber")
randomNumber
}.delay(5000, TimeUnit.MILLISECONDS)
interval
.observeOn(Schedulers.io())
.filter { it != 0L }
.delaySubscription<Int>(delayedRandomNumber)
.withLatestFrom(delayedRandomNumber, BiFunction<Long, Int, String> { second, randomNumber ->
"$randomNumber mod $second = ${randomNumber%second}"
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
Log.d("LogTag", it)
}
interval - 很明显,这每秒都会发出值(在我的例子中,它是从 EditText 发出的用户输入)
delayedRandomNumber - 这会生成一个随机数并在 5 秒后发出。我只需要生成一次但现在我不知道如何生成(在我的例子中它是来自服务器的 json 城市树)
delaySubscription - 我正在使用此运算符等待随机数。如果我不使用它,我将不会获得第二个值 1、2、3 的值(在我的例子中,我需要从第一个字母开始,因为它是基于树的数据——我有这样的约束)
withLatestFrom - 我使用这个运算符来避免每次都生成随机数(在我的例子中,我不想每次输入改变时都从服务器获取数据)
所以我需要同时使用delaySubscription和withLatestFrom。但是它通过生成随机数两次(在我的例子中加载数据两次)来制造问题
当我运行这段代码时,日志看起来是这样的:
random number = -1870536123
random number = -1834197628
-1870536123 mod 1 = 0
-1870536123 mod 2 = -1
-1870536123 mod 3 = 0
-1870536123 mod 4 = -3
-1870536123 mod 5 = -3
-1870536123 mod 6 = -3
如您所见,随机数生成了两次。
还有其他方法可以解决这个问题吗?如果是怎么办?
因为delayedRandomNumber
是cold observable或者单播。每个订阅都有自己的生产者(在您的情况下 Observable.fromCallable 内的随机数生成是生产者)。
为避免此问题,您可以使用 share 运算符多播 delayedRandomNumber
。
val delayedRandomNumber =
Observable.fromCallable {
val randomNumber = Random().nextInt()
Log.d("LogTag", "random number = $randomNumber")
randomNumber
}.delay(5000, TimeUnit.MILLISECONDS)
.share()
输出
random number = -942235082
result=-942235082
-942235082 mod 1 = 0
result=-942235082
-942235082 mod 2 = 0
result=-942235082
-942235082 mod 3 = -2
也请阅读 blog by Dan Lew,因为我发现它在遇到多播可观察对象问题时很有帮助。