混合搭配协程和 Rxjava

Mix and match Coroutines and Rxjava

Coroutines and RxJava3

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

我想知道是否有办法从 viewModelScope.launch 范围和 return fetchRecentUseCase.execute().

的结果中删除 Rxjava 代码

基本上,viewModelScope.launch 是否有可能 return 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 
    }
}

非常感谢

使用协同程序,return 异步生成单个项目的方法是使用 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())
}