Android中如何在ViewModel存储分页数据?解决设备旋转丢数据问题
解决Android设备旋转时分页数据丢失的问题
这个问题我做新闻类App的时候也碰到过,核心原因就是你的ViewModel只存了当前请求的单页数据,而且Activity重建后没从ViewModel里恢复完整的历史数据集。下面给你一步步的修复方案:
1. 让ViewModel维护完整的分页数据集
原来的topHeadlines只保存当前请求回来的单页数据,我们需要改成在ViewModel内部维护一个所有已加载文章的列表,每次请求新页时把数据追加进去,再对外发送完整的数据集:
NewsApiViewModel(application: Application) : AndroidViewModel(application) { // 内部存储所有已加载的文章 private val _allArticles = mutableListOf<Article>() // 对外暴露完整的文章列表LiveData val topHeadlines = MutableLiveData<List<Article>>() val networkLiveData = MutableLiveData<Boolean>() // 新增:对外暴露是否已加载全部数据的LiveData val isAllDataLoaded = MutableLiveData<Boolean>() fun fetchTopHeadlines(pageNumber: Int) { if (!getApplication<Application>().hasNetworkConnection()) { networkLiveData.value = false return } val destinationService = ServiceBuilder.buildService(DestinationService::class.java) val requestCall = destinationService.getTopHeadlines( AppConstants.COUNTRY_INDIA, AppConstants.PAGE_SIZE, pageNumber, AppConstants.NEWS_API_KEY ) requestCall.enqueue(object : Callback<TopHeadlines> { override fun onFailure(call: Call<TopHeadlines>, t: Throwable) { Log.e("ANKUSH", "$t ") networkLiveData.value = false } override fun onResponse(call: Call<TopHeadlines>, response: Response<TopHeadlines>) { networkLiveData.value = true if (response.isSuccessful && response.body()?.status == AppConstants.STATUS_OK) { response.body()?.articles?.let { newArticles -> // 将新页数据追加到总列表 _allArticles.addAll(newArticles) // 发送完整的数据集给观察者 topHeadlines.postValue(_allArticles.toList()) // 判断是否还有更多数据:新页数据量小于每页大小,说明没有更多了 isAllDataLoaded.postValue(newArticles.size < AppConstants.PAGE_SIZE) } } } }) } }
2. 修改Activity的观察逻辑,恢复完整数据
首先要替换掉observeForever(这个方法容易引发内存泄漏,尽量不用),改用生命周期感知的observe方法;其次,现在ViewModel返回的是完整的文章列表,Adapter需要直接更新整个数据集:
fun observeAndUpdateData() { // 观察完整的文章列表,Activity重建时会自动收到ViewModel保存的所有数据 activity.viewModel.topHeadlines.observe(activity) { allArticles -> isDataLoading = false checkAndShowLoader(isDataLoading) // 如果用的是RecyclerView的ListAdapter,用submitList自动处理Diff更新 activity.adapter.submitList(allArticles) // 如果是自定义Adapter,改成设置完整数据集的方法,比如: // activity.adapter.setArticles(allArticles) } // 观察是否已加载全部数据 activity.viewModel.isAllDataLoaded.observe(activity) { loaded -> activity.isAllDataLoaded = loaded } // 观察网络状态 activity.viewModel.networkLiveData.observe(activity) { hasNetwork -> // 这里可以处理无网络的提示逻辑 } } fun getTopHeadlines(pageNumber: Int) { if (activity.isAllDataLoaded) return isDataLoading = true checkAndShowLoader(isDataLoading) activity.viewModel.fetchTopHeadlines(pageNumber) }
3. 额外优化建议
- 如果你的项目版本允许,推荐使用Android Jetpack Paging库,它能自动处理分页数据的缓存、加载状态和配置变更(比如旋转),不用手动维护数据集,代码会更简洁健壮。
- 避免在Activity中直接持有数据集,所有数据都交由ViewModel管理,Activity只负责观察和展示。
这样修改后,当设备旋转时,ViewModel会保留所有已加载的分页数据,新重建的Activity会通过观察topHeadlines LiveData获取完整的历史数据,Adapter就能恢复之前的所有内容,不会再出现数据丢失的问题了。
内容的提问来源于stack exchange,提问作者Ankush Kapoor
相关产品推荐
相关产品推荐

