You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 20:27:37