CompletableTransformer不在上游应用ApplySubscribeOn和observeOn

时间:2019-05-25 15:10:45

标签: android kotlin rx-java2

我正在使用rxKotlin,MVVM + Clean Architecture创建脱机的第一个应用程序作为我的辅助项目,昨天我决定通过使用变压器摆脱样板的SubscribeOn和ObservOn。我很快意识到,变压器的应用功能被忽略了。

这是我的基本可完成用例(交互器)的代码:

['Python', 'is', 'an', 'programming', 'language']

这是特定交互器的实现:

abstract class CompletableUseCase(private val transformer: CompletableTransformer) {

    abstract fun createCompletable(data: Map<String, Any>? = null) : Completable

    fun completable(data: Map<String, Any>? = null) : Completable {
        return createCompletable(data).compose(transformer)
    }
}

我的自定义转换器已传递给SaveRouteInteractor的构造函数:

class SaveRouteInteractor(
    transformer: CompletableTransformer,
    private val routeRepository: RouteRepository
) : CompletableUseCase(transformer) {

    companion object {
        private const val PARAM_ROUTE = "param_route"
    }

    fun saveRoute(route: Route) : Completable {
        val data = HashMap<String, Route>()
        data[PARAM_ROUTE] = route
        return completable(data)
    }

    override fun createCompletable(data: Map<String, Any>?): Completable {
        val routeEntity = data?.get(PARAM_ROUTE)

        routeEntity?.let {
            return routeRepository.saveRoute(routeEntity as Route)
        } ?: return Completable.error(IllegalArgumentException("Argument @route must be provided."))
    }
}

以及RouteRepository方法的实现:

class IOCompletableTransformer(private val mainThreadScheduler: Scheduler) : CompletableTransformer {

    override fun apply(upstream: Completable): CompletableSource {
        return upstream.subscribeOn(Schedulers.io()).observeOn(mainThreadScheduler)
    }
}

我将Room用作本地源,因此在ViewModel中调用保存交互器后,我收到IlligalStateException通知我,不允许我访问主线程上的数据库。

也许我遗漏了一些东西,但是似乎转换功能被忽略了。我调试了此方法,并将其应用到上游的subscriptionOn和observeOn。

非常感谢您的帮助, 节奏!

1 个答案:

答案 0 :(得分:1)

由于代码是部分代码,很难告诉您问题出在哪里。

例如此处:

    return localRouteSource.saveRoute(route)
        .flatMap { localID ->
            route.routeId = localID
            remoteRouteSource.saveRoute(route)
        }
        .flatMapCompletable { localRouteSource.updateRouteID(route.routeId, it) }

我想localRouteSource.saveRoute()正在使用您向我们展示的交互器,但尚不清楚remoteRouteSource.saveRoute()localRouteSource.updateRouteID()的实现方式。

它们还需要在IO线程上进行订阅。

根据经验,应该在知道需要时切换线程。

换句话说,您应该在知道您正在做IO的地方使用subscribeOn(),该位置应尽可能接近实际工作。当您知道需要在UI线程中获得这些结果并且可能会在其他线程中获得时,将使用ObserveOn。

在您的示例中,绝对不需要继续使用observeOn(MAIN_THREAD),只有在您想要显示结果时才需要({我想)。

其他一些事情:

此代码

override fun createCompletable(data: Map<String, Any>?): Completable {
    val routeEntity = data?.get(PARAM_ROUTE)

    routeEntity?.let {
        return routeRepository.saveRoute(routeEntity as Route)
    } ?: return Completable.error(IllegalArgumentException("Argument @route must be provided."))
}

它是在调用该方法时而不是在预订completable时评估的。

换句话说,当您调用该方法时,它将破坏Rx契约并计算data?.get(PARAM_ROUTE)。如果它是不可变的,则没有什么区别,但是如果它可以在执行期间更改值,则应将其包装在Completable.defer { }

最后,在这里

        .flatMap { localID ->
            route.routeId = localID
            remoteRouteSource.saveRoute(route)
        }

您正在修改链外的某物(route.routeId = localID),这称为副作用。

请谨慎对待此类内容,Rx的构建方式更加安全,可用于不可变对象。

我个人不会介意的,只要您了解正在发生的事情以及何时可能造成问题。