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
相关产品推荐
相关产品推荐

