Android开发:如何在ViewModel生命周期外保留状态至应用关闭?
问题:Fragment切换后ViewModel状态丢失
我是Android开发新手,遇到一个问题:ViewModel原本保存着Fragment的状态变更数据,但导航到其他Fragment后,ViewModel就不再保留这些状态。我希望用户在某个Fragment修改内容后,切换到其他Fragment再返回时,能看到之前的修改。需求是仅在应用未关闭时保留状态,不想用SharedPreferences、Room这类持久化存储,想知道符合最佳实践的常规实现方式。
布局代码
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="homeViewModel" type="com.android.example.presentation.home.HomeViewModel" /> </data> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".presentation.home.HomeFragment"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" android:keepScreenOn="true"> <TextView android:id="@+id/sampleText" android:text="@{String.valueOf(homeViewModel.sampleText)}" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.5" /> <Button android:id="@+id/sampleButton" android:onClick="@{() -> homeViewModel.samplePressed()}" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="32dp" android:text="Button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/sampleText" /> </androidx.constraintlayout.widget.ConstraintLayout> </FrameLayout> </layout>
ViewModel代码
class HomeViewModel : ViewModel() { private val _sampleText = MutableLiveData(0) val sampleText : LiveData<Int> get() = _sampleText fun samplePressed() { _sampleText.postValue(1) } }
解决方案:使用长生命周期的ViewModel
核心原因
你的ViewModel丢失状态,是因为默认情况下,Fragment的ViewModel和自身生命周期绑定——当Fragment被销毁(比如导航到其他Fragment时原Fragment可能被销毁),ViewModel也会随之清除。要保留状态,需要让ViewModel的生命周期长于单个Fragment。
实现方式
1. 绑定到Activity生命周期
在Fragment中获取ViewModel时,指定Activity作为ViewModel的生命周期所有者:
// HomeFragment中获取ViewModel的代码 val homeViewModel = ViewModelProvider(requireActivity())[HomeViewModel::class.java]
此时ViewModel会和Activity的生命周期绑定,只要Activity未销毁,ViewModel就会保留状态,Fragment切换时数据不会丢失。
2. 绑定到NavGraph生命周期(适用于Jetpack Navigation)
如果项目使用Jetpack Navigation组件,可以将ViewModel绑定到对应导航图,这样同一导航图下的Fragment共享状态:
// HomeFragment中获取ViewModel的代码 val navController = findNavController() val navViewModelStoreOwner = navController.getViewModelStoreOwner(R.id.your_nav_graph_id) val homeViewModel = ViewModelProvider(navViewModelStoreOwner)[HomeViewModel::class.java]
这种方式更灵活,状态仅在当前导航图范围内保留,不会污染整个Activity的ViewModel池。
注意事项
- 不要在ViewModel中持有Fragment或Activity的引用,避免内存泄漏。
- 如果需要在进程重启(如系统回收内存)后也保留状态,可以结合
SavedStateHandle,但你的需求仅需应用未关闭时保留,上述两种方法已足够。
内容的提问来源于stack exchange,提问作者kallis
相关产品推荐
相关产品推荐

