android - 在 Android Jetpack Compose 中使用 State 时出现 java.lang.IllegalStateException

标签 android kotlin kotlin-coroutines android-jetpack-compose

我有 ViewModel使用 Kotlin 密封类为 UI 提供不同的状态。另外,我使用 androidx.compose.runtime.State对象来通知 UI 状态变化。
如果 MyApi 出现错误请求发生,我把 UIState.FailureMutableState对象,然后我得到 IllegalStateException :

 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:1524)
        at androidx.compose.runtime.snapshots.SnapshotKt.current(Snapshot.kt:1764)
        at androidx.compose.runtime.SnapshotMutableStateImpl.setValue(SnapshotState.kt:797)
        at com.vladuken.compose.ui.category.CategoryListViewModel$1.invokeSuspend(CategoryListViewModel.kt:39)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Viem型号代码:
@HiltViewModel
class CategoryListViewModel @Inject constructor(
    private val api: MyApi
) : ViewModel() {

    sealed class UIState {
        object Loading : UIState()
        data class Success(val categoryList: List<Category>) : UIState()
        object Error : UIState()
    }

    val categoryListState: State<UIState>
        get() = _categoryListState
    private val _categoryListState =
        mutableStateOf<UIState>(UIState.Loading)

    init {
        viewModelScope.launch(Dispatchers.IO) {
            try {
                val categories = api
                    .getCategory().schemas
                    .map { it.toDomain() }
                _categoryListState.value = UIState.Success(categories)

            } catch (e: Exception) {
                //this does not work
                _categoryListState.value = UIState.Error
            }
        }
    }

}
我试图延迟设置 UIState.Error - 它有效,但我认为这不是正常的解决方案:
viewModelScope.launch(Dispatchers.IO) {
            try {
                val categories = api
                    .getCategory().schemas
                    .map { it.toDomain() }
                _categoryListState.value = UIState.Success(categories)

            } catch (e: Exception) {
                //This works 
                delay(10)
                _categoryListState.value = UIState.Error
            }
        }
我在 Composable 函数中观察到 State 对象,如下所示:
@Composable
fun CategoryScreen(
    viewModel: CategoryListViewModel,
    onCategoryClicked: (Category) -> Unit
) {
    when (val uiState = viewModel.categoryListState.value) {
        is CategoryListViewModel.UIState.Error -> CategoryError()
        is CategoryListViewModel.UIState.Loading -> CategoryLoading()
        is CategoryListViewModel.UIState.Success -> CategoryList(
            categories = uiState.categoryList,
            onCategoryClicked
        )
    }
}
撰写版本:1.0.0-beta03如何处理密封类UIState与撰写 State这样它就不会抛出 IllegalStateException?

最佳答案

因此,经过更多尝试解决此问题后,我找到了解决方案。
https://stackoverflow.com/a/66892156/13101450 的帮助下答案我知道快照是事务性的,并且在 ui 线程上运行 - 更改调度程序有帮助:

viewModelScope.launch(Dispatchers.IO) {
            try {
                val categories = api
                    .getCategory().schemas
                    .map { it.toDomain() }
                _categoryListState.value = UIState.Success(categories)

            } catch (e: Exception) {
                withContext(Dispatchers.Main) {
                    _categoryListState.value = UIState.Error
                }
            }
        }

关于android - 在 Android Jetpack Compose 中使用 State 时出现 java.lang.IllegalStateException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66891349/

相关文章:

java - 在回调 rxjava 中返回 Observable

android - react-native: 有没有办法同时运行 iOS 模拟器和 Android 模拟器?

android - 如何实现相同但用更少的代码(或使用一些Kotlin扩展功能)

kotlin - Kotlin Coroutine Flow api是否具有Rx Subject等桥接工具?

java - 无法加载admob广告错误:3 ERROR_CODE_NO_FILL

java - 如何在另一张纸上书写时显示文字?

android - 使用 Apache 许可版本 2.0 许可的作品是否可以免费使用?

android - 如何在Interactor/UseCase中获取CoroutineScope

android - 注入(inject)到 Hilt 未实例化的任意 Logic 类中

kotlin - Kotlin 协程中的挂起函数是什么意思?