Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ViewModel: Error on loading long list in IO Dispatcher

I want to load a long list inside my ViewModel class, queried from database. Data will then be shown using LazyColumn. When loading in IO Dispatcher using kotlin coroutine it throws exception but no problem when loading in Main Dispatcher.

ViewModel Class:

class TestViewModel: ViewModel() {
val itemList = mutableStateListOf<TestModel>()

init {
    viewModelScope.launch(Dispatchers.IO){
        loadList()
    }
}

Error Message:

E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-1
Process: in.rachika.composetest2, PID: 19469
java.lang.IllegalStateException: Reading a state that was created after the snapshot was taken or in a snapshot that has not yet been applied
    at androidx.compose.runtime.snapshots.SnapshotKt.readError(Snapshot.kt:1518)
    at androidx.compose.runtime.snapshots.SnapshotKt.current(Snapshot.kt:1758)
    at androidx.compose.runtime.snapshots.SnapshotStateList.add(SnapshotStateList.kt:374)
    at in.rachika.composetest2.Tests.ViewModel.TestViewModel.loadList(TestViewModel.kt:24)
    at in.rachika.composetest2.Tests.ViewModel.TestViewModel.access$loadList(TestViewModel.kt:13)
    at in.rachika.composetest2.Tests.ViewModel.TestViewModel$1.invokeSuspend(TestViewModel.kt:19)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
    at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
like image 758
Rahul Avatar asked Oct 25 '25 17:10

Rahul


1 Answers

Snapshots are transactional and run on ui thread. You are attempting to create a snapshot on the IO thread. If you want to do your data loading on the IO thread, you need to switch back to the UI thread after you've retrieved the data. Example:

class MyViewModel: ViewModel() {
    fun getData() {
        viewModelScope.launch(Dispatchers.IO) {
            // Get Data
            val data = someAPI.getData()

            withContext(Dispatchers.Main) {
                // Display the data...
                displayData(data)
            }
        }
    }
}
like image 62
Johann Avatar answered Oct 27 '25 07:10

Johann