ViewModel:在IO调度程序中加载长列表时出错



我想在ViewModel类中加载一个从数据库查询的长列表。然后将使用LazyColumn显示数据。当使用kotlin协程在IO Dispatcher中加载时,它抛出异常,但在Main Dispatcher加载时没有问题。

ViewModel类:

class TestViewModel: ViewModel() {
val itemList = mutableStateListOf<TestModel>()
init {
viewModelScope.launch(Dispatchers.IO){
loadList()
}
}

错误消息:

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)

快照是事务性的,在ui线程上运行。您正试图在IO线程上创建快照。如果要在IO线程上加载数据,则需要在检索数据后切换回UI线程。示例:

class MyViewModel: ViewModel() {
fun getData() {
viewModelScope.launch(Dispatchers.IO) {
// Get Data
val data = someAPI.getData()
withContext(Dispatchers.Main) {
// Display the data...
displayData(data)
}
}
}
}

根据@Johann的建议,我已经解决了我的问题,下面是我的更新代码:

class TestViewModel: ViewModel() {
val itemList = mutableStateListOf<TestModel>()
init {
viewModelScope.launch(Dispatchers.IO){
loadList()
}
}
private fun loadList() {
for(i in 0..20){
val groupName = "${i + 1}. STICKY HEADER #"
val childList = mutableListOf<TestModel>()
for(t in 0..Random.nextInt(10, 20)){
childList.add(TestModel(
isHeader = false,
GroupId = UUID.randomUUID(),
GroupName = groupName,
ItemName = "${t + 1}. This is an CHILD ITEM... #${i + 1} - ${Random.nextInt(1001, 5001)}",
children = ArrayList()
)
)
}
//change the scope just before adding data class to mutableStateList
//because mutableStateList automatically notifies LazyColumn about this data update.
viewModelScope.launch(Dispatchers.Main){
itemList.add(TestModel(
isHeader = true,
GroupId = UUID.randomUUID(),
GroupName = groupName,
ItemName = "",
children = childList
))
}
}
}

谢谢@Johann,我将您的回答标记为已接受。

最新更新