在runInTransaction块中的suspend方法

问题描述

我使用以下代码出现编译错误

只能在协程体内调用悬浮函数

有人可以向我解释为什么吗?我需要做些什么才能使其工作(不使用@Transaction批注)?

override suspend fun replaceAccounts(newAccounts: List<Account>) {
    database.runInTransaction {
        database.accountDao().deleteallAccounts() // I have the error on this line
        database.accountDao().insertAccounts(newAccounts) // Here too
    }
}

@Dao
abstract class AccountDao : BaseDao<AccountEntity> {

    @Query("DELETE FROM Account")
    abstract suspend fun deleteallAccounts()

}

预先感谢您的帮助

解决方法

对于suspend函数,请使用withTransaction而不是runInTransaction

, 限制IO绑定和其他长时间运行的操作(例如数据库或API调用)直接在主线程中运行(否则可能导致程序无响应)。协程就像轻量级线程,它们在一个线程中异步运行。

我建议您阅读https://kotlinlang.org/docs/reference/coroutines/coroutine-context-and-dispatchers.html上的《协程》指南

要回答您的问题,您需要设置一个协程作用域和一个用于使协程运行的调度程序线程。最简单的是这样的:

GlobalScope.launch(Dispatchers.IO) {
    replaceAccounts(newAccounts)
}

它将在IO线程(处理IO任务的主线程之外的线程)上的GlobalScope(协程的“生命周期”绑定到整个应用程序的生命周期)中运行协程。

编辑 我喜欢@ IR42的答案。在此基础上,使用withTransaction可以让Room处理执行数据库操作的线程,并有助于限制数据库的并发性。

GlobalScope.launch(Dispatchers.Main) {
    replaceAccounts(newAccounts)
}

override suspend fun replaceAccounts(newAccounts: List<Account>) {
    database.withTransaction {
        database.accountDao().deleteAllAccounts() // I have the error on this line
        database.accountDao().insertAccounts(newAccounts) // Here too
    }
}

通过Room自己的文章之一查看有关此文章的更多信息:https://medium.com/androiddevelopers/threading-models-in-coroutines-and-android-sqlite-api-6cab11f7eb90