第五章:数据层—网络请求与Repository
第五章数据层 — 网络请求与 Repository数据层的职责统一管理数据来源网络/本地为 ViewModel 提供干净的数据接口。5.1 Retrofit 网络请求ApiService 接口定义interfaceApiService{GET(products)suspendfungetArticleList(Query(limit)limit:Int):ProductListResponse}RetrofitManager 单例objectRetrofitManager{privateconstvalBASE_URLhttps://dummyjson.com/valapiService:ApiServicebylazy{Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build().create(ApiService::class.java)}}为什么用 suspend挂起函数在协程中执行不阻塞主线程网络请求是耗时操作必须在后台执行5.2 数据模型// ArticleBean.kt - 商品/文章数据模型dataclassArticleBean(valid:Int,valtitle:String,valdescription:String,valthumbnail:String,valprice:Double0.0,valrating:Double0.0,valbrand:String,valcategory:String,valstock:Int0,)// ProductListResponse.kt - API 响应包装dataclassProductListResponse(valproducts:ListArticleBean,valtotal:Int0,valskip:Int0,vallimit:Int0,)JSON 响应示例{products:[...],total:100,skip:0,limit:10}GsonConverterFactory 自动将 JSON 解析为 data class。5.3 Repository 模式ArticleRepository — 文章列表仓库objectArticleRepository{privatevarcachedArticles:ListArticleBeanemptyList()suspendfungetArticleList():ListArticleBean{vallistRetrofitManager.apiService.getArticleList(10).products cachedArticleslist// 写入内存缓存returnlist}fungetArticleById(id:Int):ArticleBean?cachedArticles.find{it.idid}// 从缓存查询}ProfileRepository — 用户仓库本地示例数据objectProfileRepository{suspendfungetProfile():ProfileUser{delay(300)// 模拟网络延迟returndemoProfileUser// 返回本地示例数据}}5.4 内存缓存策略// 首页请求数据 → 写入 cachedArticles// 详情页按 ID 查询 → 从 cachedArticles 查找objectArticleRepository{privatevarcachedArticles:ListArticleBeanemptyList()suspendfungetArticleList():ListArticleBean{vallistRetrofitManager.apiService.getArticleList(10).products cachedArticleslist// 缓存returnlist}fungetArticleById(id:Int):ArticleBean?cachedArticles.find{it.idid}}缓存特点特性说明内存缓存保存在对象变量中应用关闭消失单例模式object 单例全局唯一查找方式find by id局限性详情页依赖列表先执行5.5 ViewModel 中调用 RepositoryclassHomeViewModel:ViewModel(){privatevarsourceListmutableListOfArticleBean()privateval_uiStateMutableStateFlowHomeUiState(HomeUiState.Loading)valuiState:StateFlowHomeUiState_uiState.asStateFlow()init{loadData()}funloadData(){viewModelScope.launch{_uiState.valueHomeUiState.Loadingtry{valresultArticleRepository.getArticleList()// suspend 调用sourceListresult.toMutableList()_uiState.valueHomeUiState.Success(articlesresult)}catch(e:Exception){_uiState.valueHomeUiState.Error(e.message?:加载失败)}}}}流程viewModelScope.launch开启协程调用ArticleRepository.getArticleList()suspend成功 → 写入 sourceList 更新 _uiState失败 → 更新 _uiState 为 Error5.6 错误处理网络请求可能失败ViewModel 需要捕获异常viewModelScope.launch{_uiState.valueHomeUiState.Loadingtry{valresultArticleRepository.getArticleList()_uiState.valueHomeUiState.Success(articlesresult)}catch(e:Exception){e.printStackTrace()_uiState.valueHomeUiState.Error(messagee.message?:加载失败请稍后重试)}}Composable 根据 UiState 显示不同界面when(uiState){isHomeUiState.Loading-CircularProgressIndicator()isHomeUiState.Error-ErrorView(messageuiState.message,onRetryonRetry)isHomeUiState.Success-SuccessView(articlesuiState.articles)}5.7 总结Retrofit Gson 管理网络请求ApiService 定义接口RetrofitManager 构建实例Repository 模式统一数据来源网络/本地ArticleRepository 同时负责网络获取与内存缓存ViewModel 通过 suspend 函数调用 Repositorytry-catch 捕获异常更新 Error 状态上一章第四章Navigation Compose 页面导航 下一章第六章UI 组件与 Material3 主题