【问题标题】:how to have wait for last task and results for each in coroutine on Android?如何在 Android 的协程中等待最后一个任务和结果?
【发布时间】:2022-01-22 07:03:08
【问题描述】:

我有两个任务。两者都将数据加载到视图模型(例如LoadDataList1UseCaseLoadDataList2UseCase)。 当新的片段启动时,数据应该被加载到视图模型中。但是当任何加载过程完成时,它所获取的数据应该被加载到视图(回收器视图),但只有当两者都完成时,进度条才会被隐藏。

我想出一些类似下面但不起作用的方法。我想念什么?看起来如何正确的方法?

class LoadDataList1UseCase {
   operator fun invoke() = flow { 
      delay(3_000)
      emit("a")
   }
}
class LoadDataList2UseCase {
   operator fun invoke() = flow { emit("b")}
}

//------------ method in view model:
suspend fun loadData() = withContext(Dispatchers.IO) {
   loadDataList1
      .onEatch { /*update screan*/}
   loadDataList2
      .onEatch { /*update screan*/}
}

并在 runBlocking 中运行它

我是协程的新手。在 rx 中,我会尝试混合 combineLatest 和 doOnComplite

【问题讨论】:

    标签: android kotlin kotlin-coroutines kotlin-flow


    【解决方案1】:

    你用类似于 RxJava 的方式来做,它甚至被命名为combine()

    loadDataList1
        .combine(loadDataList2, ::Pair)
        .collect { (first, second) ->
            /*update screen*/
        }
    

    【讨论】:

      【解决方案2】:

      你可以试试这样的:

      suspend fun saveInDb() {
          val value = GlobalScope.async {
             delay(1000)
             println("thread running on [${Thread.currentThread().name}]")
             10
          }
          println("value =  ${value.await()} thread running on [${Thread.currentThread().name}]")
      } 
      

      await 将等待协程完成,然后运行它下面的代码

      fun onClick(view: View) {
          res = ""
          button.isEnabled = false
          GlobalScope.launch(Dispatchers.Main){ // launches coroutine in main thread
               updateUi()
          }
      }
      
      suspend fun updateUi(){
          val value = GlobalScope.async { // creates worker thread
             res = withContext(Dispatchers.Default) {
                test()
             }
          }
          println(value.await()) //waits for workerthread to finish
          button.isEnabled = true //runs on ui thread as calling function is on Dispatchers.main
      }
      

      【讨论】:

        【解决方案3】:
        • 您可以使用merge 函数同时合并流。在这种情况下,collect action lambda 将在任一流中发出数据时被调用。在你的ViewModel 类中:

          class MyViewModel(...) : ViewModel() {
          
              fun loadData() = viewModelScope.launch {
                merge(loadDataList1(), loadDataList2())
                    .collect {
                        // update UI (RecyclerView)
                    }
                // both flows are finished, hide progress bar here
              }
          }
          
        • 还有combine函数(不是扩展函数)接受Flows合并和transform块,它定义如下:

          fun combine(flow: Flow, flow2: Flow, transform: suspend (T1, T2) -> R): Flow

          您可以在 ViewModel 类中使用它:

          class MyViewModel(...) : ViewModel() {
            init {
                combine(
                    loadDataList1(),
                    loadDataList2()
                ) { result1, result2 ->
                    // use result1 and result2
                    // hide progress
                }.launchIn(viewModelScope) // Terminal flow operator that launches the collection of the given flow in the scope. It is a shorthand for scope.launch { flow.collect() }.
            }
          }
          

          上述方法结合Flows 并调用transformresult1result2 参数仅当两者都可用时。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-01-01
          • 2023-03-08
          • 2021-05-13
          • 2016-06-15
          • 2019-06-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多