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
相关产品推荐
相关产品推荐

