Coroutine called by event that requires another coroutine to finish.

huangapple go评论62阅读模式
英文:

Coroutine called by event that requires another coroutine to finish

问题

在我的ViewModel中,我有一个从UI调用的函数。它可能会在一秒内被调用多次。

数据来自条形码扫描ViewModel。我通过UI将其从一个ViewModel传递到另一个ViewModel,以保持简单和重用条形码扫描ViewModel

为了简单起见,让我们假设我有类似以下的代码:

// 从片段调用(观察另一个ViewModel上的某个属性)
public fun processScannedBarcode(barcode: String) {
    // 在necessaryData准备好后处理数据(非空?)
    val item = findItemByBarcode(barcode)
}

private var dataFromApi: ArrayList<Item>?

private fun loadNecessaryDataFromTheApi() {
    viewModelScope.launch {
        canReload = false
        dataFromApi = myapi.getDataFromApi() // 在内部挂起的函数
        canReload = true
    }
}

// 从片段按钮点击调用
public fun reloadNecessaryDataFromTheApi() {
    loadNecessaryDataFromTheApi()
}

init {
    loadNecessaryDataFromTheApi()
}

我的处理所需的数据可能还没有准备好,因为它来自API。我必须推迟该处理,并在数据准备好时恢复。

我可以简单地使用一些队列和线程来解决这个问题,但也许可以使用Kotlin协程来实现?

英文:

In my ViewModel I have a function that is called from UI. It can be called many times per second.

Data comes from barcode scanner ViewModel. I'm passing it from one ViewModel to another thru UI for simplicity and to reuse barcode scanner ViewModel.

For simplicity lets assume that I have something like this:

// called from the fragment (that observes some property on the another viewmodel)
public fun processScannedBarcode(barcode : String){
    // process data after necessaryData is ready (not null?)
    val item = findItemByBarcode(barcode)
}

private var dataFromApi: ArrayList&lt;Item&gt;?

private fun loadNecessaryDataFromTheApi(){
    viewModelScope.launch {
        canReload = false
        dataFromApi = myapi.getDataFromApi() // suspend fun inside
        canReload = true
    }
}

// called from the fragment button click
public fun reloadNecessaryDataFromTheApi(){
    loadNecessaryDataFromTheApi()
}

init {
    loadNecessaryDataFromTheApi()
}

My data required to process may be not ready yet because it comes from the API. I have to deferr that processing and resume when data is ready.

I could simply solve this with some Queue and a Thread, but maybe it is possible to do that with Kotlin coroutines?

答案1

得分: 1

作为您的 `loadNecessaryDataFromTheApi()` 只是设置属性很难观察或等待它您需要使用一些同步工具如锁通道等在这种情况下可能最容易的方法是保留必要数据的 `Deferred`

```kotlin
public suspend fun processScannedBarcode(barcode : String){
    val data = dataFromApi.await()
    val item = findItemByBarcode(barcode)
}

private val dataFromApi = CompletableDeferred<ArrayList<Item>>()

private fun loadNecessaryDataFromTheApi(){
    viewModelScope.launch {
        canReload = false
        dataFromApi.complete(myapi.getDataFromApi())
        canReload = true
    }
}

一些注意事项:

  1. 如果要等待某些内容,我们必须将 processScannedBarcode 声明为挂起函数。
  2. 如果希望 reloadNecessaryDataFromTheApi() 重新延迟处理条形码,只需用新的 deferred 替换 dataFromApi

<details>
<summary>英文:</summary>

As your `loadNecessaryDataFromTheApi()` only sets properties, it is not that easy to observe it or wait for it. You need to use some synchronization utility like locks, channels, etc. In this case it will be probably the easiest to keep a `Deferred` of the necessary data:

```kotlin
public suspend fun processScannedBarcode(barcode : String){
    val data = dataFromApi.await()
    val item = findItemByBarcode(barcode)
}

private val dataFromApi = CompletableDeferred&lt;ArrayList&lt;Item&gt;&gt;()

private fun loadNecessaryDataFromTheApi(){
    viewModelScope.launch {
        canReload = false
        dataFromApi.complete(myapi.getDataFromApi())
        canReload = true
    }
}

Some notes:

  1. We have to make processScannedBarcode suspend if it is going to wait for something.
  2. If you want reloadNecessaryDataFromTheApi() to defer processing barcodes again, simply replace dataFromApi with a new deferred.

huangapple
  • 本文由 发表于 2023年2月6日 12:09:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/75357268.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定