You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin新手求密封类(sealed classes)在Android开发中的实用示例

嘿,作为刚接触Kotlin的Android开发者,密封类确实是个能让代码更简洁安全的好工具——尤其是在处理状态、UI事件或者多类型数据分支的时候。我给你几个Android开发里最常用的场景示例,看完你应该就能快速上手了!

1. 处理UI数据状态(最实用的场景)

Android请求数据时,通常会遇到加载中、成功返回数据、加载失败、空数据这几种固定状态。用密封类可以完美枚举所有可能的状态,而且编译器会帮你检查when表达式是否覆盖了所有分支,避免遗漏。

// 定义密封类封装UI状态
sealed class UiState<out T> {
    // 加载中(无数据,用object单例即可)
    object Loading : UiState<Nothing>()
    // 加载成功(携带泛型数据)
    data class Success<out T>(val data: T) : UiState<T>()
    // 加载失败(携带错误信息)
    data class Error(val message: String) : UiState<Nothing>()
    // 空数据状态
    object Empty : UiState<Nothing>()
}

// 在ViewModel中使用,管理数据请求状态
class UserViewModel : ViewModel() {
    private val _userState = MutableLiveData<UiState<User>>()
    val userState: LiveData<UiState<User>> = _userState

    fun fetchUserInfo() {
        _userState.value = UiState.Loading
        // 模拟网络请求
        viewModelScope.launch {
            try {
                val user = apiService.getUser()
                _userState.value = if (user != null) {
                    UiState.Success(user)
                } else {
                    UiState.Empty
                }
            } catch (e: Exception) {
                _userState.value = UiState.Error(e.message ?: "加载失败,请重试")
            }
        }
    }
}

// 在Activity/Fragment中观察状态并更新UI
viewModel.userState.observe(this) { state ->
    when (state) {
        UiState.Loading -> showLoadingProgress()
        is UiState.Success -> renderUserInfo(state.data)
        is UiState.Error -> showErrorSnackbar(state.message)
        UiState.Empty -> showEmptyDataView()
        // 无需写else分支,编译器会确保所有密封类子类都被覆盖
    }
}
2. 统一管理UI事件(比如导航、弹窗)

很多时候我们需要在ViewModel中发送一次性UI事件(比如跳转到详情页、显示弹窗),用密封类可以把所有事件类型统一封装,避免定义多个零散的LiveData。

// 密封类定义所有可能的UI事件
sealed class UiEvent {
    data class NavigateToDetail(val userId: String) : UiEvent()
    data class ShowToast(val message: String) : UiEvent()
    object ShowLogoutConfirmation : UiEvent()
}

// ViewModel中发送事件
class UserViewModel : ViewModel() {
    // 用SingleLiveEvent避免事件重复消费(也可以用EventWrapper封装LiveData)
    private val _uiEvent = SingleLiveEvent<UiEvent>()
    val uiEvent: LiveData<UiEvent> = _uiEvent

    fun onUserItemClicked(userId: String) {
        _uiEvent.value = UiEvent.NavigateToDetail(userId)
    }

    fun onLogoutButtonClicked() {
        _uiEvent.value = UiEvent.ShowLogoutConfirmation
    }
}

// 在Activity中处理事件
viewModel.uiEvent.observe(this) { event ->
    when (event) {
        is UiEvent.NavigateToDetail -> {
            val intent = Intent(this, UserDetailActivity::class.java)
            intent.putExtra("USER_ID", event.userId)
            startActivity(intent)
        }
        is UiEvent.ShowToast -> Toast.makeText(this, event.message, Toast.LENGTH_SHORT).show()
        UiEvent.ShowLogoutConfirmation -> showLogoutDialog()
    }
}
3. 处理多类型列表数据(比如RecyclerView的多Item)

如果你的RecyclerView有多种Item类型(文章、视频、广告),用密封类可以明确所有可能的Item类型,让Adapter的类型处理更安全。

// 密封类定义所有列表Item类型
sealed class ContentItem {
    data class Article(val title: String, val content: String) : ContentItem()
    data class Video(val title: String, val playUrl: String, val duration: Int) : ContentItem()
    data class Ad(val adId: String, val adContent: String) : ContentItem()
}

// RecyclerView Adapter中使用
class ContentAdapter(private val items: List<ContentItem>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    override fun getItemViewType(position: Int): Int {
        return when (items[position]) {
            is ContentItem.Article -> 0
            is ContentItem.Video -> 1
            is ContentItem.Ad -> 2
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        return when (viewType) {
            0 -> ArticleViewHolder(inflater.inflate(R.layout.item_article, parent, false))
            1 -> VideoViewHolder(inflater.inflate(R.layout.item_video, parent, false))
            2 -> AdViewHolder(inflater.inflate(R.layout.item_ad, parent, false))
            else -> throw IllegalArgumentException("未知的Item类型")
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val item = items[position]
        when (holder) {
            is ArticleViewHolder -> holder.bind(item as ContentItem.Article)
            is VideoViewHolder -> holder.bind(item as ContentItem.Video)
            is AdViewHolder -> holder.bind(item as ContentItem.Ad)
        }
    }

    override fun getItemCount() = items.size
}

简单总结下:密封类的核心优势是有限的子类集合,编译器会帮我们强制检查所有可能的分支,避免遗漏情况,让代码更安全、可读性更强。在Android开发里,UI状态管理、事件分发、多类型数据展示这几个场景用得最多,你可以先从UI状态这个场景入手,慢慢熟悉它的用法。

内容的提问来源于stack exchange,提问作者omega1100100

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:15:28