I am playing around with Kotlin Flow, Coroutines and Room. I am trying to insert data into my Room Database from my Repository.
When inserting a single item there is no problem but if I try to insert a list of items, the execution aborts and there is following message logged to the console:
I/Choreographer: Skipped 47 frames! The application may be doing too much work on its main thread.
I don't understand why the insert operation is executed on the main thread because according to the docs, a suspended DAO operation should always be executed in a Coroutine initiated internally by Room (which ultimately should run on a background thread). I also tried to run the insert call in another Scope explicitly (withContext(Dispatchers.IO) { ... }) but there is no difference.
Here is what my code looks like:
ViewModel:
fun setStateEvent(stateEvent: StateEvent) {
viewModelScope.launch {
when (stateEvent) {
is StateEvent.GetItems -> {
repository.getItems().onEach { dateState ->
_dataState.value = dateState
}.launchIn(viewModelScope)
}
}
}
}
Repository:
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>)
I also tried to debug and find the source of the problem but I had no luck. Would be glad if anyone could tell me what's wrong.
From what I see, there is no problem here. Choreographer messages can be misleading, it might have nothing to do with the main thread. I often see this when debugging, probably due to the debugger overhead. Inflation of heavy layouts can also cause it.
Also you don't need the
launchIn(viewModelScope)
because the flow is already collected in that scope. Just usecollect()
. And unlike what the other answers may suggest, you are right in saying the Room automatically switches the thread when usingsuspend
DAO methods.