【问题标题】:Mix and match Coroutines and Rxjava混合搭配 Coroutines 和 Rxjava
【发布时间】:2021-08-03 08:55:22
【问题描述】:

Coroutines and RxJava3

我有以下方法,它首先调用一个挂起方法,并在同一个启动范围内我对 RxJava 进行了 2 次调用。

我想知道是否有办法将 Rxjava 代码从viewModelScope.launch 范围中删除并返回fetchRecentUseCase.execute() 的结果。

基本上,viewModelScope.launch 是否有可能返回 listOfProducts 而不是在启动范围内执行所有操作?

fun loadRecentlyViewed() {
    viewModelScope.launch {
        val listOfProducts = withContext(Dispatchers.IO) {
            fetchRecentUseCase.execute()
        }

        val listOfSkus = listOfProducts.map { it.sku }

        if (listOfSkus.isNotEmpty()) {
            loadProductUseCase.execute(listOfSkus)
                .subscribeOn(schedulersFacade.io)
                .flatMap(convertProductDisplayUseCase::execute)
                .map { /* work being done */ }
                .observeOn(schedulersFacade.ui)
                .subscribeBy(
                    onError = Timber::e,
                    onSuccess = { }
                )
        }
    }
}

挂起方法的用例

class FetchRecentUseCaseImp() {
    override suspend fun execute(): List<Products> {
        // Call to network 
    }
}

在此先感谢

【问题讨论】:

  • loadProductUseCase.execute 的返回类型究竟是什么?你说你想返回产品列表,但你的代码看起来像是将该列表映射到 Skus,然后使用 Rx 执行另一个操作将它们转换回产品,也许?
  • 抱歉,我已经编辑了这个问题。基本上,我想从viewModelScope.launch 返回结果。

标签: kotlin rx-java kotlin-coroutines


【解决方案1】:

使用协程,返回异步生成的单个项目的方法是使用suspend 函数。因此,您无需启动协程,而是将函数标记为suspend,并将阻塞或异步回调函数转换为非阻塞代码。

启动协程的地方通常是在 UI 交互(点击侦听器)或首次创建类时(在 Android 上,这是在 ViewModel 构造函数或 Fragment 的onViewCreated() 中的地方)。

作为旁注,任何suspend 函数期望调用者必须指定调度程序是违反约定的。如果需要,它应该在内部委托,例如:

class FetchRecentUseCaseImp() {
    override suspend fun execute(): List<Products> = withContext(Dispatchers.IO) {
        // Synchronous call to network 
    }
}

但是,如果您使用的是 Retrofit 之类的库,您只需发出请求并 await() 它而不指定调度程序,因为 await() 本身就是一个挂起函数。

所以你的函数应该是这样的:

suspend fun loadRecentlyViewed(): List<SomeProductType> {
  val listOfSkus = fetchRecentUseCase.execute().map(Product::sku)
  if (listOfSkus.isEmpty()) {
    return emptyList()
  }
  return runCatching {
    loadProductUseCase.execute(listOfSkus) // A Single, I'm assuming
      .await() // Only if you're not completely stripping Rx from project
      .map { convertProductDisplayUseCase.execute(it).await() } // Ditto for await()
      .toList()
      .flatten()
  }.onFailure(Timber::e)
    .getOrDefault(emptyList())
}

【讨论】:

    猜你喜欢
    • 2012-03-28
    • 1970-01-01
    • 1970-01-01
    • 2022-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多