什么时候不使用RxJava的Observable?



例如,我的应用程序中有一个简单的Manager,我试图在其中保留所有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())
    }
}

这是一个简单的类,用于计算时间,并在应用程序必须锁定时从shouldLock()发出true

以下是我使用它的方法:

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()组合在一起。

这让我相信,对于appLockManager.setLocked()这样的方法,我不应该使用RxJava。

我应该在这里使用Observables吗特别适用于setLocked()/setUnlocked()/resetLockTimer()方法,它们只更新AppLockManager,根本不返回数据。

使用嵌套订阅是一种糟糕的代码气味。要在完成另一个Observable之后使用另一个,可以使用concat Observables。

你的代码可以更简单。例如,不用这个:

.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
                       }
                })
}

@dwursteisen提出的另一种解决方案是使用Completable。根据变更日志,它只是变成了@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())
}

此外,shoudlLock()中的Observable可以替换为Single(发出一个项目的Observable(。

相关内容

  • 没有找到相关文章

最新更新