简体   繁体   English

协程在其他 function 中等待任务与相同的 scope

[英]Coroutine waiting for task in other function with same scope

I have a function like this that inserts a new row in a table with rowId:我有一个像这样的 function 在带有 rowId 的表中插入一个新行:

@Composable
fun AddNewCustomer() {
    val db = CustomersDatabase.getDatabase(LocalContext.current)
    val coroutineScope = rememberCoroutineScope()
    val createMainEntity = {
        coroutineScope.launch(Dispatchers.IO) {
            val rowId = db.customersDao().getLast()!!.id + 1
            db.customersDao().insertPrimaries(CustomersEntity(rowId, null, null, null))

        }
    }
    createMainEntity()
    otherFunc(db, coroutineScope)      
    
}

and in another function, I insert a new row to another table:在另一个 function 中,我在另一个表中插入了一个新行:

@Composable
private fun otherFunc(
    db: CustomersDatabase,
    coroutineScope: CoroutineScope,
) {
        val save = {
                coroutineScope.launch(Dispatchers.IO) {
                    delay(100)
                    val rowId = db.customersDao().getLast()!!.id
                    db.customersDao().insertPhone(PhoneNumberEntity(phone = "", customerId = rowId , field = "" ))
   }
   }
        save()
}

I want to save() in otherFunc waits till createMainEntity finishes, with delay, I can be sure the createMainEntity finishes first but it's a dirty way how can I do that better.我想 save() 在otherFunc等到 createMainEntity 完成,延迟,我可以确定createMainEntity首先完成,但这是一种肮脏的方式,我怎样才能做得更好。

Based on what I understand about Compose, these functions absolutely should not be Composables.根据我对 Compose 的了解,这些函数绝对不应该是 Composables。 A Composable function must not affect external state because it must be idempotent.可组合 function 不得影响外部 state,因为它必须是幂等的。 You could call one of these functions from a listener lambda in one of your Composables, but you must not call them directly.您可以从您的其中一个 Composable 中的侦听器 lambda 调用这些函数之一,但不能直接调用它们。

Accordingly, the function name should not start with a capital letter by convention.因此,按照惯例,function 名称不应以大写字母开头。 I also added "Async" to the name to signify that it does something asynchronously (by launching a coroutine that runs separately).我还在名称中添加了“Async”以表示它异步执行某些操作(通过启动单独运行的协程)。

To call the other function after the Room transaction is complete, call it inside the coroutine that is performing the transaction.要在 Room 事务完成后调用另一个 function,请在执行事务的协程内调用它。

Also, it is convoluted to create a lambda function solely to immediately call it and do nothing else with it, so I removed that.此外,创建一个 lambda function 只是为了立即调用它而不做任何其他事情,所以我删除了它。 Your fixed function looks like:您固定的 function 看起来像:

fun addNewCustomerAsync(coroutineScope: CoroutineScope) {
    val db = CustomersDatabase.getDatabase(LocalContext.current)
    coroutineScope.launch(Dispatchers.IO) {
        val rowId = db.customersDao().getLast()!!.id + 1
        db.customersDao().insertPrimaries(CustomersEntity(rowId, null, null, null))
        createMainEntity() 
        otherFunc(db, coroutineScope) 
    }
}

Your other function should simply be a suspend function.您的其他 function 应该只是暂停 function。 A dispatcher doesn't need to be specified because it doesn't call any blocking functions.不需要指定调度程序,因为它不调用任何阻塞函数。

private suspend fun otherFunc(db: CustomersDatabase) {
    delay(100) // Why are you doing this? Probably can remove this line.
    val rowId = db.customersDao().getLast()!!.id
    db.customersDao().insertPhone(PhoneNumberEntity(phone = "", customerId = rowId , field = "" ))
}

You can call addNewCustomerAsync() from a listener/callback in one of your Composable functions, but you cannot call it directly.您可以在您的可组合函数之一中从侦听器/回调调用addNewCustomerAsync() ,但不能直接调用它。 Really, these kinds of function that interact with a database should be in a ViewModel, so I would remove the coroutineScope parameter from addNewCustomerAsync() and have it use viewModelScope .真的,这些与数据库交互的 function 应该在 ViewModel 中,所以我会从addNewCustomerAsync()中删除coroutineScope参数并让它使用viewModelScope

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM