当前位置: 首页 > news >正文

第七章:状态管理实战与架构总结

第七章:状态管理实战与架构总结

本章通过完整的首页/个人中心/详情页数据流分析,巩固 MVVM + Repository + UiState 架构模式。


7.1 首页完整数据流

// 1. HomePage 调用 viewModel@ComposablefunHomePage(navController:NavController){valviewModel:HomeViewModel=viewModel()valuiStatebyviewModel.uiState.collectAsState()HomePageContent(uiState=uiState,onArticleClick={article->navController.navigate(AppRoutes.detailRoute(article.id))},onSearchChange=viewModel::updateSearchKeyword,onSortConfirm=viewModel::sortByTitle,onRetry=viewModel::loadData,)}// 2. ViewModel 管理状态classHomeViewModel:ViewModel(){privatevarsourceList=mutableListOf<ArticleBean>()privateval_uiState=MutableStateFlow<HomeUiState>(HomeUiState.Loading)valuiState:StateFlow<HomeUiState>=_uiState.asStateFlow()init{loadData()}funloadData(){viewModelScope.launch{_uiState.value=HomeUiState.Loadingtry{valresult=ArticleRepository.getArticleList()sourceList=result.toMutableList()_uiState.value=HomeUiState.Success(articles=result)}catch(e:Exception){_uiState.value=HomeUiState.Error(e.message?:"加载失败")}}}funupdateSearchKeyword(keyword:String){valfiltered=if(keyword.isBlank())sourceListelsesourceList.filter{it.title.contains(keyword,ignoreCase=true)}_uiState.value=HomeUiState.Success(articles=filtered,searchKeyword=keyword)}funsortByTitle(){valcurrent=_uiState.valueas?HomeUiState.Success?:return_uiState.update{HomeUiState.Success(articles=current.articles.sortedBy{it.title},searchKeyword=current.searchKeyword,)}}}// 3. Composable 渲染不同状态@ComposablefunHomePageContent(uiState:HomeUiState,...){when(uiState){isHomeUiState.Loading->Box(contentAlignment=Alignment.Center){CircularProgressIndicator()}isHomeUiState.Error->Column{Text(uiState.message);Button(onRetry){Text("重试")}}isHomeUiState.Success->HomeSuccessContent(uiState)}}

7.2 个人中心完整数据流

// ViewModelclassProfileViewModel:ViewModel(){privateval_uiState=MutableStateFlow<ProfileUiState>(ProfileUiState.Loading)valuiState:StateFlow<ProfileUiState>=_uiState.asStateFlow()init{loadProfile()}funloadProfile(){viewModelScope.launch{_uiState.value=ProfileUiState.Loadingtry{valuser=ProfileRepository.getProfile()// 本地示例数据,300ms 延迟_uiState.value=ProfileUiState.Success(user=user)}catch(e:Exception){_uiState.value=ProfileUiState.Error(e.message?:"加载失败")}}}funsetNotificationEnabled(enabled:Boolean){_uiState.update{state->if(stateisProfileUiState.Success)state.copy(notificationEnabled=enabled)elsestate}}}// UiState 定义sealedinterfaceProfileUiState{dataobjectLoading:ProfileUiStatedataclassSuccess(valuser:ProfileUser,valnotificationEnabled:Boolean=true):ProfileUiStatedataclassError(valmessage:String):ProfileUiState}

特点:

  • 通知开关状态保存在Success.notificationEnabled
  • 调用setNotificationEnabled直接更新 UI 状态,无需网络请求

7.3 详情页完整数据流

// DetailPage 绑定 ViewModel@ComposablefunDetailPage(navController:NavController,articleId:Int){valviewModel:DetailViewModel=viewModel(key="detail_$articleId",factory=DetailViewModelFactory(articleId),)valuiStatebyviewModel.uiState.collectAsState()DetailPageContent(uiState=uiState,onBackClick={navController.popBackStack()})}// ViewModelclassDetailViewModel(privatevalarticleId:Int):ViewModel(){privateval_uiState=MutableStateFlow<DetailUiState>(DetailUiState.Loading)valuiState:StateFlow<DetailUiState>=_uiState.asStateFlow()init{loadArticle()}funloadArticle(){viewModelScope.launch{_uiState.value=DetailUiState.Loadingvalarticle=ArticleRepository.getArticleById(articleId)// 从缓存读取_uiState.value=if(article!=null)DetailUiState.Success(article)elseDetailUiState.Error("未找到该商品")}}}// Factory(因为 ViewModel 有构造参数)classDetailViewModelFactory(privatevalarticleId:Int):ViewModelProvider.Factory{overridefun<T:ViewModel>create(modelClass:Class<T>):T{returnDetailViewModel(articleId)asT}}

7.4 三页面对比总结

维度首页个人中心详情页
UiStateHomeUiStateProfileUiStateDetailUiState
数据来源API 网络请求本地示例数据内存缓存
搜索/过滤支持不支持不支持
排序支持不支持不支持
通知开关不支持支持不支持
ViewModel 参数articleId
工厂模式

7.5 架构统一性

每个页面的代码结构完全一致:

XxxPage(navController) → viewModel() 获取 ViewModel → collectAsState() 监听 UI 状态 → XxxPageContent(uiState, callbacks) → when(uiState) { Loading / Success / Error }

Repository 职责清晰:

  • ArticleRepository.getArticleList()→ 网络 + 缓存
  • ArticleRepository.getArticleById(id)→ 缓存查询
  • ProfileRepository.getProfile()→ 本地示例数据

7.6 课后练习建议

练习难度说明
添加商品收藏功能简单本地状态,参考通知开关
实现下拉刷新中等配合PullToRefreshBox
添加商品分类筛选中等首页增加筛选按钮
详情页独立请求 API困难改为GET products/{id}

7.7 后续可改进方向

方向说明
详情页独立 API当前依赖列表缓存,可改为GET products/{id}
统一错误处理Repository 返回Result<T>,统一错误类型
依赖注入引入 Hilt/Koin 替代 object 单例,便于测试
本地持久化添加 Room 数据库,支持离线缓存
单元素测试Mock Repository 测试 ViewModel

7.8 总结

  • 三个页面遵循统一的 MVVM + sealed UiState 模式
  • ViewModel 管理状态,Composable 只负责渲染
  • Repository 统一数据来源,网络/本地/缓存分层
  • 状态变化通过 StateFlow 观察,collectAsState() 转为 Compose 状态
  • UI 与业务逻辑完全解耦,便于测试与维护

恭喜完成 MyFirstCompose 教程学习!🎉

上一章:第六章:UI 组件与 Material3 主题

http://www.jsqmd.com/news/842526/

相关文章:

  • 2026香柚汁厂家推荐:NFC果汁原料厂家,原料甄选,新鲜锁鲜 - 栗子测评
  • 概率计算与突触可塑性:隐藏p-bit机制解析
  • JDBC(四):Statement
  • 滑动平均滤波的“黄金分割点”:如何为你的传感器数据选择最佳窗口大小?(以AD7734为例)
  • 兼容多系统的音视频时长统计工具
  • 健身房私教管理系统 01:用户体系与多角色注册闭环
  • 2026年热门的钢制侧向防火卷帘多家厂家对比分析 - 品牌宣传支持者
  • Docker Compose部署Nginx Proxy Manager保姆级教程:从端口映射到数据持久化全解析
  • STM32F108C8T6小白入门特训营__1.4GPIO.C 代码分析
  • 零基础API开发指南:零基础小白从入门到精通,高效打通数据“任督二脉”?
  • 为什么 SAP S/4HANA 的前端更常用 SAPUI5,而不是 React、Vue 或 Angular
  • * 阿里云百炼:免部署直接调用云端大模型
  • 从选题到定稿不熬夜:2026 年 10 款 AI 毕业论文工具实测,Paperxie 领衔全流程通关
  • COSI-Corr安装保姆级教程:从官网注册到ENVI环境变量配置,一次搞定
  • 2026职场进阶学数据分析的价值
  • 护眼钢化膜是智商税?圆偏振光+AR降反射实测,观复盾用硬核技术给出答案
  • 【NotebookLM戏剧研究辅助实战指南】:20年戏剧学者亲授AI赋能文本细读的5大黄金工作流
  • HarmonyOS 6学习:从视频加载到长截图——性能优化实战全解析
  • 学Simulink——基于 PWM 加相移混合控制的双向 DC-DC 变换器仿真
  • SBA系列生物传感分析仪的工作原理是什么?
  • Spring AI Alibaba零基础速成(2) ---- Ollama安装与使用
  • 玩客云直刷Armbian集成宝塔:一站式搭建个人服务器
  • 深度强化学习在卫星姿态控制中的应用与挑战
  • Warcraft Helper完整指南:让经典魔兽争霸3在现代Windows系统焕发新生
  • NotebookLM投稿窗口期预警:这7本SCI期刊正试点AI辅助审稿,截止前48小时提交优先处理!
  • PPTX判断包含图表id
  • Godot游戏开发:有限状态机(FSM)框架YAFSM原理与应用实战
  • 从JT/T 808到1078:构建道路运输车辆卫星定位系统的协议栈全景解析
  • coze 实战:萌宠摆摊视频工作流,一键自动生成趣味短片
  • 利用Token Plan套餐实现大模型API用量与成本的可控管理