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 约束失败)。
由于主线程的消息,我没有考虑这个。
谢谢大家的帮助。
我正在研究 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 约束失败)。
由于主线程的消息,我没有考虑这个。
谢谢大家的帮助。