Jetpack Lifecycle 状态机详解
在上一篇文章中,对Lifecycle做了一下了解,但发现其中一个重要的知识点没有提到,就是它的状态如何转换的,里面涉及到一个状态机的概念,今天就一起来看看状态机,和状态机在Lifecycle中的使用。
状态机基础概念
状态机定义
状态机是一种数学模型,用于描述对象在其生命周期中可能经历的各种状态,以及触发状态转换的事件和条件。它包含:
- 状态(State):对象在生命周期中的稳定阶段
- 事件(Event):触发状态转换的动作
- 转换(Transition):从一个状态到另一个状态的变化过程
状态机原理
- 有限状态:对象只能处于预定义的有限状态之一
- 事件驱动:状态转换由特定事件触发
- 确定性:给定当前状态和事件,下一个状态是确定的
- 单向流动:状态转换通常遵循特定方向(如生命周期前进或回退)
Lifecycle 状态机详解
在 Jetpack Lifecycle 中,状态机精确描述了 Android 组件(Activity/Fragment)的生命周期变化:
状态(State)定义
状态 | 常量值 | 描述 |
---|---|---|
INITIALIZED |
0 | 初始状态(对象已创建但未进入生命周期) |
CREATED |
1 | onCreate() 之后,onStart() 之前 |
STARTED |
2 | onStart() 之后,onResume() 之前 |
RESUMED |
3 | onResume() 之后(完全可见在前台) |
DESTROYED |
4 | onDestroy() 之后(生命周期结束) |
事件(Event)定义
事件 | 常量值 | 对应回调 |
---|---|---|
ON_CREATE |
0 | onCreate() |
ON_START |
1 | onStart() |
ON_RESUME |
2 | onResume() |
ON_PAUSE |
3 | onPause() |
ON_STOP |
4 | onStop() |
ON_DESTROY |
5 | onDestroy() |
ON_ANY |
6 | 任意事件 |
状态转换规则
Lifecycle 使用严格的状态转换机制,确保状态转换符合 Android 生命周期逻辑:
stateDiagram-v2
[*] --> INITIALIZED
INITIALIZED --> CREATED: ON_CREATE
CREATED --> STARTED: ON_START
STARTED --> RESUMED: ON_RESUME
RESUMED --> STARTED: ON_PAUSE
STARTED --> CREATED: ON_STOP
CREATED --> DESTROYED: ON_DESTROY
DESTROYED --> [*]
note right of INITIALIZED
初始状态:组件已实例化但
未进入生命周期回调
end note
note left of CREATED
CREATED状态:
onCreate()已执行
但组件不可见
end note
note right of STARTED
STARTED状态:
onStart()已执行
组件可见但未在前台
end note
note left of RESUMED
RESUMED状态:
onResume()已执行
组件完全可见在前台
end note
详细转换流程
1. 前进流程(启动/恢复)
css
INITIALIZED
→ [ON_CREATE] → CREATED
→ [ON_START] → STARTED
→ [ON_RESUME] → RESUMED
示例场景:Activity 启动
java
// 状态变化流程:
// 1. Activity 实例化:INITIALIZED
// 2. onCreate() 执行:分发 ON_CREATE 事件 → CREATED
// 3. onStart() 执行:分发 ON_START 事件 → STARTED
// 4. onResume() 执行:分发 ON_RESUME 事件 → RESUMED
2. 后退流程(暂停/停止)
css
RESUMED
→ [ON_PAUSE] → STARTED
→ [ON_STOP] → CREATED
→ [ON_DESTROY] → DESTROYED
示例场景:用户按下返回键
java
// 状态变化流程:
// 1. onPause() 执行:分发 ON_PAUSE 事件 → STARTED
// 2. onStop() 执行:分发 ON_STOP 事件 → CREATED
// 3. onDestroy() 执行:分发 ON_DESTROY 事件 → DESTROYED
3. 部分回退流程(如切换到其他应用)
css
RESUMED → [ON_PAUSE] → STARTED → [ON_STOP] → CREATED
示例场景:用户按 Home 键
java
// 状态变化流程:
// 1. onPause() 执行:ON_PAUSE → STARTED
// 2. onStop() 执行:ON_STOP → CREATED
// 当用户返回时:
// 3. onRestart() 执行(无对应事件)
// 4. onStart() 执行:ON_START → STARTED
// 5. onResume() 执行:ON_RESUME → RESUMED
状态转换规则说明
-
不可跳跃状态:
- 不能从
CREATED
直接到RESUMED
,必须经过STARTED
- 不能从
RESUMED
直接到CREATED
,必须经过STARTED
- 不能从
-
事件与状态对应关系:
ON_CREATE
事件后状态总是变为CREATED
ON_START
事件后状态总是变为STARTED
ON_RESUME
事件后状态总是变为RESUMED
ON_PAUSE
事件后状态总是变为STARTED
ON_STOP
事件后状态总是变为CREATED
ON_DESTROY
事件后状态总是变为DESTROYED
-
特殊转换情况:
- 配置变更时:先执行完整销毁流程到
DESTROYED
,然后重新初始化 - 从后台返回:从
CREATED
→STARTED
→RESUMED
,不经过INITIALIZED
- 配置变更时:先执行完整销毁流程到
状态机实现原理
在 LifecycleRegistry
中的核心处理逻辑:
java
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
State next = getStateAfter(event);
moveToState(next);
}
static State getStateAfter(Event event) {
switch (event) {
case ON_CREATE:
case ON_STOP:
return State.CREATED;
case ON_START:
case ON_PAUSE:
return State.STARTED;
case ON_RESUME:
return State.RESUMED;
case ON_DESTROY:
return State.DESTROYED;
case ON_ANY:
// 不会改变状态
}
throw new IllegalArgumentException("Unexpected event value " + event);
}
private void moveToState(State next) {
if (mState == next) return;
mState = next;
if (mHandlingEvent || mAddingObserverCounter != 0) {
// 延迟处理
mNewEventOccurred = true;
return;
}
mHandlingEvent = true;
sync(); // 同步状态给所有观察者
mHandlingEvent = false;
}
状态机使用注意事项
-
状态同步:
- 当添加新观察者时,会立即收到从当前状态回溯到初始状态的所有事件
- 例如:当前状态为 RESUMED 时添加观察者,会依次收到:
ON_CREATE → ON_START → ON_RESUME
-
状态查询:
kotlin// 获取当前状态 val currentState = lifecycle.currentState // 检查是否至少处于某个状态 if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) { // 安全执行需要 STARTED 状态的操作 }
-
边界情况处理:
ON_DESTROY
事件可能不会在配置变更时触发- 避免在
ON_DESTROY
中执行关键资源释放,优先使用ON_STOP
-
状态与事件关系:
graph LR A[事件] --> B[状态变化] ON_CREATE --> CREATED ON_START --> STARTED ON_RESUME --> RESUMED ON_PAUSE --> STARTED ON_STOP --> CREATED ON_DESTROY --> DESTROYED
实际应用场景
场景:视频播放器状态管理
kotlin
class VideoPlayerObserver(private val context: Context) : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
// 状态:STARTED
// 初始化播放器但不自动播放
initPlayer()
}
override fun onResume(owner: LifecycleOwner) {
// 状态:RESUMED
// 开始播放
startPlayback()
}
override fun onPause(owner: LifecycleOwner) {
// 状态:STARTED
// 暂停播放(保持播放状态)
pausePlayback()
}
override fun onStop(owner: LifecycleOwner) {
// 状态:CREATED
// 释放播放器资源
releasePlayer()
}
}
// 在Activity中使用
class VideoActivity : AppCompatActivity() {
private lateinit var playerObserver: VideoPlayerObserver
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
playerObserver = VideoPlayerObserver(this)
lifecycle.addObserver(playerObserver)
}
}
状态转换跟踪:
-
Activity 启动:
INITIALIZED → CREATED → STARTED → RESUMED
- 依次触发:
onCreate() → onStart() → onResume()
- 播放器:初始化 → 开始播放
- 依次触发:
-
用户按下 Home 键:
RESUMED → STARTED → CREATED
- 依次触发:
onPause() → onStop()
- 播放器:暂停 → 释放资源
- 依次触发:
-
用户返回应用:
CREATED → STARTED → RESUMED
- 依次触发:
onRestart() → onStart() → onResume()
- 播放器:重新初始化 → 继续播放
- 依次触发:
总结
Jetpack Lifecycle 的状态机:
- 提供了标准化的生命周期状态管理
- 通过明确定义的状态和事件确保转换的可靠性
- 支持状态查询和状态条件检查
- 自动处理观察者的状态同步
- 简化了生命周期相关组件的开发
理解状态机的工作原理能帮助开发者:
- 编写更可靠的与生命周期相关的代码
- 避免常见的内存泄漏和状态不一致问题
- 创建更易于维护的生命周期感知组件
- 正确处理边界情况和异常状态转换
通过合理利用 Lifecycle 状态机,可以显著提升 Android 应用的稳定性和用户体验。