各种 Android 系统操作都可能会影响 Fragment 的状态。为确保用户状态得以保存,Android 框架会自动保存和恢复 Fragment 及返回堆栈。因此,您需要确保 Fragment 中的任何数据也得到保存和恢复。
下表概述了导致 Fragment 丢失状态的操作,以及各种类型的状态是否会持久存在于这些变更中。表中提到的状态类型如下:
- 变量:Fragment 中的局部变量。
- 视图状态:Fragment 中由一个或多个视图拥有的任何数据。
- SavedState:此 Fragment 实例固有的数据,应保存在
onSaveInstanceState()
中。 - NonConfig:从外部来源(例如服务器或本地代码库)拉取的数据,或用户创建的、在提交后发送到服务器的数据。
通常,变量与SavedState的处理方式相同,但下表区分了两者,以演示各种操作对它们的影响。
操作 | 变量 | 视图状态 | SavedState | NonConfig |
---|---|---|---|---|
添加到返回堆栈 | ✓ | ✓ | x | ✓ |
配置变更 | x | ✓ | ✓ | ✓ |
进程终止/重新创建 | x | ✓ | ✓ | ✓* |
已移除,未添加到返回堆栈 | x | x | x | x |
宿主已完成 | x | x | x | x |
* 使用 ViewModel 的 Saved State 模块,可在进程终止后保留 NonConfig 状态。
表 1:各种 Fragment 破坏性操作及其对不同状态类型的影响。
我们来看一个具体示例。假设有一个屏幕,它会生成一个随机字符串,将其显示在 TextView
中,并提供在发送给朋友之前编辑字符串的选项。

在此示例中,假设用户按下编辑按钮后,应用会显示一个 EditText
视图,用户可以在其中编辑消息。如果用户点击 CANCEL,则 EditText
视图应清空,并且其可见性应设置为 View.GONE
。这样的屏幕可能需要管理四项数据,以确保无缝体验。
数据 | 类型 | 状态类型 | 说明 |
---|---|---|---|
seed |
Long |
NonConfig | 用于随机生成新善行的种子。在 ViewModel 创建时生成。 |
randomGoodDeed |
字符串 |
SavedState + 变量 | 在 Fragment 首次创建时生成。randomGoodDeed 会被保存,以确保用户在进程终止并重新创建后仍能看到相同的随机善行。 |
isEditing |
Boolean |
SavedState + 变量 | 当用户开始编辑时,布尔值标志设置为 true 。isEditing 会被保存,以确保在 Fragment 重新创建时,屏幕的编辑部分仍可见。 |
已编辑文本 | Editable |
视图状态(由 EditText 拥有) |
EditText 视图中已编辑的文本。EditText 视图会保存此文本,以确保用户正在进行的更改不会丢失。 |
表 2:随机文本生成器应用必须管理的状态。
以下各部分介绍了如何通过破坏性操作正确管理数据状态。
视图状态
视图负责管理其自身状态。例如,当视图接受用户输入时,视图有责任保存和恢复该输入以处理配置更改。所有 Android 框架提供的视图都有其自己的 onSaveInstanceState()
和 onRestoreInstanceState()
实现,因此您无需在 Fragment 中管理视图状态。
例如,在上述场景中,编辑后的字符串保存在 EditText
中。EditText
知道它正在显示的文本值,以及其他详细信息,例如任何选定文本的开头和结尾。
视图需要一个 ID 来保留其状态。此 ID 在 Fragment 及其视图层次结构中必须是唯一的。没有 ID 的视图无法保留其状态。
<EditText android:id="@+id/good_deed_edit_text" android:layout_width="match_parent" android:layout_height="wrap_content" />
如表 1 所述,视图通过所有不移除 Fragment 或销毁宿主的操作来保存和恢复其 ViewState
。
SavedState
您的 Fragment 负责管理少量动态状态,这些状态是 Fragment 功能的组成部分。您可以使用 Fragment.onSaveInstanceState(Bundle)
保留易于序列化的数据。与 Activity.onSaveInstanceState(Bundle)
类似,您放入 Bundle 中的数据会通过配置更改和进程终止与重新创建而保留,并且在 Fragment 的 onCreate(Bundle)
、onCreateView(LayoutInflater, ViewGroup, Bundle)
和 onViewCreated(View, Bundle)
方法中可用。
继续前面的示例,randomGoodDeed
是显示给用户的善行,而 isEditing
是一个标志,用于确定 Fragment 是显示还是隐藏 EditText
。此保存状态应使用 onSaveInstanceState(Bundle)
进行持久化,如下例所示:
Kotlin
override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putBoolean(IS_EDITING_KEY, isEditing) outState.putString(RANDOM_GOOD_DEED_KEY, randomGoodDeed) }
Java
@Override public void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(IS_EDITING_KEY, isEditing); outState.putString(RANDOM_GOOD_DEED_KEY, randomGoodDeed); }
要在 onCreate(Bundle)
中恢复状态,请从 Bundle 中检索存储的值:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) isEditing = savedInstanceState?.getBoolean(IS_EDITING_KEY, false) randomGoodDeed = savedInstanceState?.getString(RANDOM_GOOD_DEED_KEY) ?: viewModel.generateRandomGoodDeed() }
Java
@Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { isEditing = savedInstanceState.getBoolean(IS_EDITING_KEY, false); randomGoodDeed = savedInstanceState.getString(RANDOM_GOOD_DEED_KEY); } else { randomGoodDeed = viewModel.generateRandomGoodDeed(); } }
如表 1 所述,请注意,当 Fragment 放置在返回堆栈上时,变量会保留下来。将它们视为保存状态可确保它们在所有破坏性操作中持久存在。
NonConfig
NonConfig 数据应放置在 Fragment 外部,例如在 ViewModel
中。在上面的示例中,seed
(我们的 NonConfig 状态)在 ViewModel
中生成。维护其状态的逻辑由 ViewModel
拥有。
Kotlin
public class RandomGoodDeedViewModel : ViewModel() { private val seed = ... // Generate the seed private fun generateRandomGoodDeed(): String { val goodDeed = ... // Generate a random good deed using the seed return goodDeed } }
Java
public class RandomGoodDeedViewModel extends ViewModel { private Long seed = ... // Generate the seed private String generateRandomGoodDeed() { String goodDeed = ... // Generate a random good deed using the seed return goodDeed; } }
ViewModel
类本身允许数据在配置变更(例如屏幕旋转)后继续存在,并在 Fragment 放置在返回堆栈上时保留在内存中。在进程终止和重新创建后,ViewModel
会重新创建,并生成一个新的 seed
。向您的 ViewModel
添加 SavedState
模块可使 ViewModel
在进程终止和重新创建后保留简单状态。
其他资源
如需了解有关管理 Fragment 状态的更多信息,请参阅以下其他资源。
Codelabs
- 感知生命周期的组件 Codelab