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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 11:20:31