英文:
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<Item>?
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
}
}
一些注意事项:
- 如果要等待某些内容,我们必须将
processScannedBarcode
声明为挂起函数。 - 如果希望
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<ArrayList<Item>>()
private fun loadNecessaryDataFromTheApi(){
viewModelScope.launch {
canReload = false
dataFromApi.complete(myapi.getDataFromApi())
canReload = true
}
}
Some notes:
- We have to make
processScannedBarcode
suspend if it is going to wait for something. - If you want
reloadNecessaryDataFromTheApi()
to defer processing barcodes again, simply replacedataFromApi
with a new deferred.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论