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

Android MVVM架构下ViewModel横竖屏切换未保留状态问题求助

问题根因与修复方案

1. 接口重复请求是核心原因

你在onCreateView生命周期中每次都调用viewmodel.getDataFromApi(),ViewModel本身确实会在配置变更时存活,但横竖屏切换触发Fragment重建时,这段代码会再次执行,触发重复请求覆盖原有LiveData的值,自然看起来像状态没有保留。
修复方案:在ViewModel中增加数据存在判断,或将请求逻辑移入ViewModel的init块,仅在ViewModel首次创建时执行一次请求。

// NewsViewModel.kt 调整代码
class NewsViewModel : ViewModel() {
    private val _newsMutableLiveData: MutableLiveData<NewsList> = MutableLiveData()
    val newsMutableLiveData : LiveData<NewsList> get() = _newsMutableLiveData

    // 初始化时执行请求,仅执行一次
    init {
        getDataFromApi()
    }

    fun getDataFromApi() {
        // 已有数据则不重复请求
        if (_newsMutableLiveData.value != null) return
        Log.i(TAG,"init")
        viewModelScope.launch(Dispatchers.IO) {
            val retrofitInstance = RetrofitInstanceDto.getRetrofitInstance().create(RetrofitServiceDto::class.java)
            val response = retrofitInstance.getDataFromApi()
            delay(1500)
            _newsMutableLiveData.postValue(response)
        }
    }
}

调整后删除NewsListFragment.kt中onCreateView里的viewmodel.getDataFromApi()调用即可。

2. Adapter初始化时机错误导致列表状态丢失

你当前在LiveData的观察者回调中才初始化Adapter,每次Fragment重建后需要等待新请求返回才会渲染列表,原有列表的滚动位置等状态自然无法保留。
修复方案:将Adapter初始化逻辑移到onCreateView中,数据返回时仅更新Adapter数据集,不要重复创建Adapter和绑定RecyclerView。

// NewsListFragment.kt 调整代码
override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?,
): View {
    binding = FragmentNewsListBinding.inflate(layoutInflater)
    Log.i(TAG,"onCreate")
    // 提前初始化Adapter和RecyclerView,不等待数据返回
    initAdapterModel()

    viewmodel.newsMutableLiveData.observe(viewLifecycleOwner, {
        if(it!=null )
        {
            hideProgressBar()
            Log.i(TAG,"Received the data")
            // 仅更新数据集,不重复创建Adapter
            newsAdapter.setLatestData(it.rows,activity)
        }
        else {
            showProgressBar()
            Toast.makeText(activity,"No data",Toast.LENGTH_LONG).show()
        }
    })
    return binding.root
}

3. 可选:保留RecyclerView滚动位置

如果需要横竖屏切换后恢复列表滚动位置,可以在Fragment销毁前保存LayoutManager状态,重建后恢复:

// NewsListFragment.kt 新增代码
private var recyclerState: Parcelable? = null

override fun onPause() {
    super.onPause()
    recyclerState = binding.recyclerView.layoutManager?.onSaveInstanceState()
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    recyclerState?.let {
        binding.recyclerView.layoutManager?.onRestoreInstanceState(it)
    }
}

内容的提问来源于stack exchange,提问作者androminor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 18:54:06