Room Coroutine 在主线程中执行

Room Coroutine is executed in main thread

我正在研究 Kotlin Flow、Coroutines 和 Room。我正在尝试将数据从我的存储库插入到我的房间数据库中。

插入单个项目时没有问题,但如果我尝试插入项目列表,执行就会中止,控制台会记录以下消息:

I/Choreographer: Skipped 47 frames!  The application may be doing too much work on its main thread.

我不明白为什么插入操作在主线程上执行,因为根据文档,挂起的 DAO 操作应该始终在 Room 内部启动的协程中执行(最终应该 运行在后台线程上)。我还尝试 运行 在另一个范围内显式插入调用 (withContext(Dispatchers.IO) { ... }) 但没有区别。

我的代码如下所示:

视图模型:

fun setStateEvent(stateEvent: StateEvent) {
    viewModelScope.launch {
        when (stateEvent) {
            is StateEvent.GetItems -> {
                repository.getItems().onEach { dateState ->
                    _dataState.value = dateState
                }.launchIn(viewModelScope)
            }
        }
    }
}

存储库:

suspend fun getItems(): Flow<DataState<List<Item>>> = flow {
    emit(DataState.Loading)
    try {
        val items = itemService.getAllItems()
        emit(DataState.Success(items))
        itemDao.insertItems(items) // The execution stops here
    } catch (e: Exception) {
        emit(DataState.Error(e))
    }
}

DAO:

@Insert
suspend fun insertItems(items: List<Item>)

我也尝试调试并找到问题的根源,但我没有运气。如果有人能告诉我哪里出了问题,我会很高兴。

您可以在执行 viewmodelScope 的 CoroutineScope 的启动中添加 Dispatchers.IO

fun setStateEvent(stateEvent: StateEvent) {
    viewModelScope.launch(Dispatchers.IO) {
        when (stateEvent) {
            is StateEvent.GetItems -> {
                repository.getItems().collect {
                for(item in it) { _dataState.value = item }
               }
            }
        }
    }
}

确保您的 gradle 中有 room-ktx 的依赖项,这将允许您在与 room

的界面中使用暂停功能
implementation "androidx.room:room-ktx:2.2.5"

参见:https://developer.android.com/jetpack/androidx/releases/room#declaring_dependencies

无论哪种方式,您都无法从房间界面中的暂停中受益。

据我所知,这里没有问题。 Choreographer messages can be misleading,可能与主线程无关。我在调试时经常看到这个,可能是由于调试器的开销。 Inflation 繁重的布局也可能导致它。

此外,您不需要 launchIn(viewModelScope),因为流已收集在该范围内。只需使用 collect()。与其他答案可能暗示的不同,您说的是正确的 Room 在使用 suspend DAO 方法时自动切换线程。

对不起大家...我原来的代码没有问题post。 我没有评估我在捕获异常时抛出的错误。所以问题完全不同(NOT NULL 约束失败)。

由于主线程的消息,我没有考虑这个。

谢谢大家的帮助。