RxJava 条件 FlatMap 清洁方式
RxJava Conditional FlatMap Cleaner Way
我正在寻找一种更简洁的方法来创建条件 flatMap()
,我已阅读 但我无法将其应用到我的代码中:
// given variables for the sake of simplicity
val stringSingle = Single.just("dog")
val isCatEat = Single.just(true)
val feedCat = Single.just(true)
// example
stringSingle
.flatMap { string ->
if (string == "cat") {
return@flatMap isCatEat()
.flatMap { isCatEat ->
if (isCatEat) { // if cat already ate, proceed immediately
Single.fromCallable { true }
} else { // if not, feed cat
feedCat()
}
}
} else {
Single.fromCallable { false }
}
}
如您所见(好吧,代码非常丑陋,嵌套呃),我想通过先检查猫是否已经吃东西来避免调用 feedCat()
。我在应用 compose()
函数时遇到问题,因为我无法重现我的情况。
您可以使用 filter
,它只会在谓词满足时发出。
我假设您想知道这只猫什么时候需要喂食。因此,我认为 observable 会更合适:
private val hasCatEaten = Single.just(true)
fun feedCat(animal: String): Observable<Unit> =
Observable.just(animal)
.filter { it == "cat" }
.flatMapSingle { hasCatEaten }
.filter { !it }
.map { Unit }
fun observeFeedCat() {
feedCat("cat")
.subscribeOn(schedulers.ioScheduler())
.observeOn(schedulers.mainScheduler())
.subscribeBy(onNext = { // Called when cat needs to be fed })
.addTo(disposables)
}
更新
这是一个更好的解决方案,可以处理这两种情况:
fun shouldFeed(animal: String): Single<Boolean> =
Single.fromCallable { animal }
.filter { it == "cat" }
.flatMap { Maybe.fromCallable { !hasEaten } }
.toSingle(false)
我对这段代码进行了单元测试(不是猫,猫吃过和没吃过)所以我对这个答案很有信心。
我将第二个 if
提取到扩展函数中
// given variables for the sake of simplicity
val stringSingle = Single.just("dog")
val isCatEat = Single.just(true)
val feedCat = Single.just(true)
// example
stringSingle
.flatMap { string ->
if (string == "cat") {
isCatEat.flatMapIfTrue { feedCat }
} else {
Single.fromCallable { false }
}
}
其中:
fun Single<Boolean>.flatMapIfTrue(mapper: (Boolean) -> Single<Boolean>): Single<Boolean> =
this.flatMapIf({ it }, mapper)
fun Single<Boolean>.flatMapIfFalse(mapper: (Boolean) -> Single<Boolean>): Single<Boolean> =
this.flatMapIf({ !it }, mapper)
fun <T> Single<T>.flatMapIf(conditions: (T) -> Boolean, mapper: (T) -> Single<T>): Single<T> =
this.flatMap {
if (conditions(it)) mapper(it)
else Single.just(it)
}
我提供了 3 个 fun
,因此您可以在其他地方重复使用它
我正在寻找一种更简洁的方法来创建条件 flatMap()
,我已阅读
// given variables for the sake of simplicity
val stringSingle = Single.just("dog")
val isCatEat = Single.just(true)
val feedCat = Single.just(true)
// example
stringSingle
.flatMap { string ->
if (string == "cat") {
return@flatMap isCatEat()
.flatMap { isCatEat ->
if (isCatEat) { // if cat already ate, proceed immediately
Single.fromCallable { true }
} else { // if not, feed cat
feedCat()
}
}
} else {
Single.fromCallable { false }
}
}
如您所见(好吧,代码非常丑陋,嵌套呃),我想通过先检查猫是否已经吃东西来避免调用 feedCat()
。我在应用 compose()
函数时遇到问题,因为我无法重现我的情况。
您可以使用 filter
,它只会在谓词满足时发出。
我假设您想知道这只猫什么时候需要喂食。因此,我认为 observable 会更合适:
private val hasCatEaten = Single.just(true)
fun feedCat(animal: String): Observable<Unit> =
Observable.just(animal)
.filter { it == "cat" }
.flatMapSingle { hasCatEaten }
.filter { !it }
.map { Unit }
fun observeFeedCat() {
feedCat("cat")
.subscribeOn(schedulers.ioScheduler())
.observeOn(schedulers.mainScheduler())
.subscribeBy(onNext = { // Called when cat needs to be fed })
.addTo(disposables)
}
更新
这是一个更好的解决方案,可以处理这两种情况:
fun shouldFeed(animal: String): Single<Boolean> =
Single.fromCallable { animal }
.filter { it == "cat" }
.flatMap { Maybe.fromCallable { !hasEaten } }
.toSingle(false)
我对这段代码进行了单元测试(不是猫,猫吃过和没吃过)所以我对这个答案很有信心。
我将第二个 if
提取到扩展函数中
// given variables for the sake of simplicity
val stringSingle = Single.just("dog")
val isCatEat = Single.just(true)
val feedCat = Single.just(true)
// example
stringSingle
.flatMap { string ->
if (string == "cat") {
isCatEat.flatMapIfTrue { feedCat }
} else {
Single.fromCallable { false }
}
}
其中:
fun Single<Boolean>.flatMapIfTrue(mapper: (Boolean) -> Single<Boolean>): Single<Boolean> =
this.flatMapIf({ it }, mapper)
fun Single<Boolean>.flatMapIfFalse(mapper: (Boolean) -> Single<Boolean>): Single<Boolean> =
this.flatMapIf({ !it }, mapper)
fun <T> Single<T>.flatMapIf(conditions: (T) -> Boolean, mapper: (T) -> Single<T>): Single<T> =
this.flatMap {
if (conditions(it)) mapper(it)
else Single.just(it)
}
我提供了 3 个 fun
,因此您可以在其他地方重复使用它