0Pricing
Kotlin Academy · 课时

使用密封类建模界面状态

使用密封类表示界面的 Loading、Success 和 Error 状态。

使用密封类建模界面状态 是 CoddyKit 上的免费 Kotlin Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Kotlin Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Kotlin Academy 课程共包含 4 节课。

界面状态问题

界面页面有多种状态:加载中、显示数据、显示错误或为空。使用布尔值(isLoading、hasError)管理这些状态很脆弱。密封类可以解决这个问题。

经典的布尔值地狱

使用相互独立的布尔值会导致不可能存在的状态。
// Fragile: isLoading=true AND hasError=true is invalid
var isLoading = false
var hasError = false
var data: List<Item>? = null
// 8 combinations, most of which are invalid!

密封状态:只有有效状态

密封类可以让无效状态无法表示。
sealed class UiState<out T>
object Loading : UiState<Nothing>()
data class Success<T>(val data: T) : UiState<T>()
data class Error(val message: String, val retryable: Boolean = true) : UiState<Nothing>()
object Empty : UiState<Nothing>()

根据状态进行渲染

使用条件表达式为每种状态渲染正确的界面。
fun render(state: UiState<List<Item>>) = when (state) {
    Loading -> showProgressBar()
    is Success -> showItems(state.data)
    is Error -> showError(state.message, state.retryable)
    Empty -> showEmptyView()
}

ViewModel 发出状态

ViewModel 通过 StateFlow 发出密封状态。
class ItemViewModel : ViewModel() {
    private val _state = MutableStateFlow<UiState<List<Item>>>(Loading)
    val state: StateFlow<UiState<List<Item>>> = _state

    fun loadItems() = viewModelScope.launch {
        _state.value = Loading
        _state.value = try {
            Success(repository.getItems())
        } catch (e: Exception) {
            Error(e.message ?: "Unknown error")
        }
    }
}

组合内部带有 Content 的状态

使用泛型密封状态来处理任意数据类型。
fun <T> loading(): UiState<T> = Loading
fun <T> success(data: T): UiState<T> = Success(data)
fun <T> error(msg: String): UiState<T> = Error(msg)

分页状态示例

密封类可以自然地为分页列表状态建模。
sealed class PageState
object Idle : PageState()
object FirstLoad : PageState()
data class Content(val items: List<Item>, val hasMore: Boolean) : PageState()
data class LoadingMore(val items: List<Item>) : PageState()
data class Error(val items: List<Item>?, val msg: String) : PageState()

转换状态

在不接触其他情况的前提下,映射成功状态。
fun <T, R> UiState<T>.mapData(transform: (T) -> R): UiState<R> = when (this) {
    is Success -> Success(transform(data))
    is Error -> this
    Loading -> Loading
    Empty -> Empty
}

使用密封状态进行测试

状态很容易测试——只需检查发出的是哪个变体。
@Test
fun testLoadingState() {
    viewModel.loadItems()
    assertEquals(Loading, viewModel.state.value)
}
@Test
fun testSuccessState() {
    viewModel.setData(listOf(item))
    assert(viewModel.state.value is Success)
}

组合状态与多个流程

单个密封状态流程比多个必须保持同步的独立流程更简洁。
// Fragile: two flows must stay in sync
val loading = MutableStateFlow(false)
val error = MutableStateFlow<String?>(null)

// Clean: one sealed state
val state = MutableStateFlow<UiState<List<Item>>>(Loading)

向状态添加元数据

密封子类型可以携带相关元数据。
data class Error(
    val message: String,
    val code: Int = 0,
    val retryable: Boolean = true,
    val timestamp: Long = System.currentTimeMillis()
) : UiState<Nothing>()

快速检查

使用密封类为界面状态建模可以解决什么关键问题?

回顾

使用密封类为界面状态建模:Loading、Success(data)、Error(message)、Empty。使用条件表达式渲染每种情况。一个包含密封类型的 StateFlow 优于多个布尔标志。下一步:嵌套密封层次结构!

常见问题解答

「使用密封类建模界面状态」课时是免费的吗?

是的 — 「使用密封类建模界面状态」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Kotlin Academy 课程的其余内容,请升级到 CoddyKit PRO。 Kotlin Academy 课程共包含 4 节课。

「使用密封类建模界面状态」这节课中我会学到什么?

使用密封类表示界面的 Loading、Success 和 Error 状态。 你通过在浏览器中直接运行的动手代码来练习 Kotlin Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Kotlin Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Kotlin Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「使用密封类建模界面状态」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Kotlin Academy 课中编写并运行代码吗?

能。每节 Kotlin Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. sealed class 与 sealed interface:分别适用于何时
  2. 密封层次结构中的穷尽式 when
  3. 使用密封类建模界面状态
  4. 嵌套与组合密封层次结构
← 返回 Kotlin Academy