ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

QueryViewState 状态机设计:reactive-mvvm-android 中 sealed class 管理加载、错误与结果的完整方案

QueryViewState 状态机设计:reactive-mvvm-android 中 sealed class 管理加载、错误与结果的完整方案 QueryViewState 状态机设计reactive-mvvm-android 中 sealed class 管理加载、错误与结果的完整方案【免费下载链接】reactive-mvvm-androidMy way to MVVM using KotlinX Coroutines and Android>项目地址: https://gitcode.com/gh_mirrors/re/reactive-mvvm-androidreactive-mvvm-android 是一个基于 KotlinX Coroutines 与 Android DataBinding 构建的 MVVM 开源项目其核心设计是用sealed class 状态机 QueryViewState统一管理加载Loading、错误Error与结果Result三种 UI 状态实现 ViewModel 与视图的自动绑定。本文带你完整拆解这套状态机方案的设计思路与落地方式 为什么需要状态机管理 UI 状态在 Android 开发中一个页面通常会同时出现多种状态正在加载、加载成功、网络出错、结果为空……如果用一堆布尔变量isLoading、hasError、isEmpty来描述很快就会出现互相矛盾的组合例如正在加载和出错同时为真。reactive-mvvm-android 的做法是把所有状态收敛成一个不可变的类型——sealed class。sealed class 的子类集合在编译期就完全封闭Kotlin 的when表达式可以穷尽所有分支编译器会帮你兜底不会出现遗漏状态的 bug。QueryViewState 状态机全貌核心文件app/src/main/java/es/ffgiraldez/comicsearch/query/base/presentation/QueryViewState.kt整个状态机只有 4 个分支职责清晰状态类型含义Idleobject初始空闲尚未发起查询Loadingobject请求进行中显示进度条ResultTdata class携带查询结果列表泛型 T 支持不同数据类型Errordata class携带ComicError错误信息三个设计亮点值得学习泛型化设计QueryViewStateout T使用协变out声明同一个状态机既能装搜索结果Volume漫画卷对象也能装搜索建议String一套代码服务多个页面。单例与数据分离Idle和Loading是无状态的用object单例避免重复创建Result和Error携带数据用data class天然获得equals与copy能力。Companion 工厂方法通过QueryViewState.idle()、loading()、result(list)、error(err)四个工厂方法创建状态调用方无需关心具体子类名可读性更强。错误类型同样使用 sealed class 定义app/src/main/java/es/ffgiraldez/comicsearch/comics/domain/Entities.kt中的ComicError区分NetworkError与EmptyResultsError让没有结果和网络失败两种语义各得其所。状态流转Flow Either 自动产出 ViewState状态如何从 Repository 流向 UI答案是Flow 响应式管线。基类SuspendQueryStateViewModelapp/src/main/java/es/ffgiraldez/comicsearch/query/base/presentation/SuspendQueryStateViewModel.kt接收一个转换器函数(FlowString) - FlowQueryViewStateT将用户输入的查询词流转换为状态流并通过asLiveData暴露为LiveDataQueryViewStateT。以搜索场景为例app/src/main/java/es/ffgiraldez/comicsearch/query/search/presentation/SuspendSearchViewModel.kt状态流转逻辑非常精炼用户每次输入触发flatMapLatest自动取消上一次未完成的请求防抖式快速搜索的关键每次请求开始时通过onStart { emit(QueryViewState.loading()) }自动插入加载态仓库返回的数据类型是 Arrow 库的EitherComicError, ListT通过扩展函数toViewState()定义在 QueryViewState.kt 底部一键折叠为Error或Result状态流开始时发出idle()作为初始状态。建议搜索场景app/src/main/java/es/ffgiraldez/comicsearch/query/sugestion/presentation/SuspendSuggestionViewModel.kt在此之上再加了debounce(400)防抖和distinctUntilChanged()去重——这正是状态即数据思想的延伸状态流可以像普通 Flow 一样用操作符自由组合。DataBinding让 UI 自动响应状态变化状态机设计的收益在 UI 层集中体现。扩展属性文件app/src/main/java/es/ffgiraldez/comicsearch/query/base/ui/QueryViewStateExt.kt为每个状态提供了安全访问器state.error非错误态返回nullstate.results非结果态返回空列表state.loading布尔值判断。视图层通过 DataBinding 的BindingAdapter把QueryViewState直接绑到控件上见app/src/main/java/es/ffgiraldez/comicsearch/query/search/ui/SearchBindingAdapters.ktProgressBar.bindProgress根据loading属性控制进度条显隐FrameLayout.bindStateVisibility出错时显示错误容器TextView.bindErrorText把错误转换为人类可读文案RecyclerView.bindStateData用results属性直接提交列表数据。ViewModel 中when逻辑一行都没有——状态一变DataBinding 自动驱动所有控件刷新。Activity 代码中完全不出现判断状态再操作控件的样板代码这就是 sealed class 状态机 DataBinding 的组合威力 ✨可测试性状态机带来的红利因为状态是纯数据单元测试可以精确断言整个状态流转序列。app/src/test/java/es/ffgiraldez/comicsearch/query/search/presentation/SearchViewModelSpec.kt中使用 Kotest Turbine 的写法非常直观断言初始状态为Idle→ 输入查询词后变为Loading→ 最终等于由toViewState()生成的预期状态。搜索建议页面同样有对应的测试app/src/test/java/es/ffgiraldez/comicsearch/query/sugestion/presentation/SuggestionViewModelSpec.kt。状态机 属性测试Arbitrary 生成随机数据让这套逻辑的回归保障非常扎实。总结这套方案能带给你什么用 sealed class 收敛所有 UI 状态编译期穷尽检查杜绝非法状态组合泛型状态机 工厂方法一套设计复用搜索、建议等多个功能页面Flow 管线中插入状态onStart发 Loading、Either折叠发 Error/Result状态流转声明式、可组合扩展属性 BindingAdapter让 DataBinding 直接消费状态UI 零样板代码状态即数据单元测试可逐步断言完整流转序列。这套仅百行代码量级的设计就是 Android MVVM 架构中响应式状态管理的一个优雅范本值得在你的项目中借鉴复用 【免费下载链接】reactive-mvvm-androidMy way to MVVM using KotlinX Coroutines and Android>项目地址: https://gitcode.com/gh_mirrors/re/reactive-mvvm-android创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表