例如,我在我的应用程序中有一个简单的管理器,我试图保留所有内容reactive
:
class AppLockManager {
private val logger = LoggerFactory.getLogger(javaClass)
private val rxHelper: RxHelper
private val securityManager: DiarySecurityManager
private var locked = false
private var lastUnlockTime: LocalDateTime? = null
constructor(rxHelper: RxHelper, securityManager: DiarySecurityManager) {
this.rxHelper = rxHelper
this.securityManager = securityManager
}
fun shouldLock(): Observable<Boolean> {
return securityManager.isSecutiryEnabled()
.doOnNext { logger.debug("isSecurityEnabled: $it") }
.map { it && !locked && isLockTimerExpired() }
.doOnNext { logger.debug("shouldLock: $it") }
.compose(rxHelper.applySchedulers())
}
private fun isLockTimerExpired(): Boolean {
if(lastUnlockTime == null) return true
val timerExpiredMoment = lastUnlockTime!!.plusSeconds(30)
val now = LocalDateTime.now().isAfter(timerExpiredMoment)
val isExpired = LocalDateTime.now().isAfter(timerExpiredMoment)
logger.debug("timerExpiredMoment: $timerExpiredMoment / now: $now; isExpired: $isExpired")
return isExpired
}
fun setLocked(): Observable<Void> {
return Observable.create<Void> {
this.locked = true
it.onCompleted()
}.compose(rxHelper.applySchedulers())
}
fun setUnlocked(): Observable<Void> {
return Observable.create<Void> {
this.locked = false
lastUnlockTime = LocalDateTime.now()
}.compose(rxHelper.applySchedulers())
}
fun resetLockTimer(): Observable<Void> {
return Observable.create<Void> {
lastUnlockTime = LocalDateTime.now()
}.compose(rxHelper.applySchedulers())
}
}
这是一个简单的课程,可以计算时间,并在必须锁定我的申请时从true
发出shouldLock()
。
我有如何使用它:
fun lockAppIfNeeded() {
appLockManager.shouldLock()
.doOnNext { logger.debug("shouldLock: $it") }
.flatMap { if(it == true) Observable.just(it) else Observable.never() } // flow down only if it == true
.flatMap { appLockManager.setLocked() } // then lock
.subscribe(sub({}, Throwable::printStackTrace, { // use onComplete as source Observable is empty
securityManager.anyPassword().subscribe {
if (it) {
view.navigateToAskPassword() // anyPassword is true
} else {
view.navigateToFirstPasswordSetup() // anyPassword is false
}
}
}))
}
看起来很难看,不是吗? :)
我找不到合适的运算符来将空的Observable(appLockManager.setLocked()
)与securityManager.anyPassword()
wwitch返回Observable组合,并发出一个项目。
这让我相信我不应该将RxJava用于像appLockManager.setLocked()
这样的方法。
我应该在这里使用Observable吗?特别适用于setLocked()
/ setUnlocked()
/ resetLockTimer()
只更新AppLockManager
并且根本不返回任何数据的方法
答案 0 :(得分:2)
使用嵌套订阅会导致代码异味。要在完成另一个Observable
之后使用另一个concat
,您可以.flatMap { if(it == true) Observable.just(it) else Observable.never() }
可观察数据。
您的代码可以更简单。例如,而不是使用它:
filter
您可以改为使用filter
。
因此,删除嵌套订阅+ fun lockAppIfNeeded() {
appLockManager.shouldLock()
.doOnNext { logger.debug("shouldLock: $it") }
.filter { it } // flow down only if it == true
.flatMap { appLockManager.setLocked() } // then lock
.ignoreElements() // throw away appLockManager items
.concatWith(securityManager.anyPassword())
.subscribe {
if (it) {
view.navigateToAskPassword() // anyPassword is true
} else {
view.navigateToFirstPasswordSetup() // anyPassword is false
}
})
}
将导致此代码:
list
答案 1 :(得分:0)
@dwursteisen提供的另一种解决方案是使用Completable
。根据{{3}},它刚刚成为@Beta
。
改进了lockAppIfNeeded()
方法:
fun lockAppIfNeeded() {
appLockManager.shouldLock()
.doOnNext { logger.debug("shouldLock: $it") }
.filter { it } // flow down only if it == true
.toCompletable()
.concatWith(appLockManager.setLocked()) // then lock
.andThen(securityManager.anyPassword())
.subscribe(sub {
if (it) {
view.navigateToAskPassword() // anyPassword is true
} else {
view.navigateToFirstPasswordSetup() // anyPassword is false
}
})
}
setLock()
返回Completable
的位置:
fun setLocked(): Completable {
return Completable.fromAction { this.locked = true }
.compose(rxHelper.applySchedulersToCompletable())
}
此外,Observable
中的shoudlLock()
可以替换为Single
(发出一个项目的Observable
)。