Android 生命周期,是每一个 Android 开发者都绕不开的痛。
早期我们习惯在:
kotlin
onStart()
onStop()
onResume()
onPause()
里面处理各种业务。
后来有了 LifecycleObserver,再到 Kotlin 协程、Flow 成为现代 Android 异步编程的重要组成部分。
如果只是从 API 的变化来看,很容易得到:
text
Lifecycle 回调
↓
LifecycleObserver
↓
Coroutine / Flow
但真正值得关注的,并不仅仅是 API 的变化。
而是背后的编程模型发生了变化:
Android 生命周期管理,正在从"生命周期事件驱动",演进到"生命周期约束下的结构化任务"。
一、最初:生命周期事件驱动
最早 Android 的生命周期模型非常简单。
Activity 提供:
kotlin
onCreate()
onStart()
onResume()
onPause()
onStop()
onDestroy()
开发者根据生命周期回调执行对应逻辑。
例如:
kotlin
override fun onStart() {
super.onStart()
startNetworkMonitor()
}
override fun onStop() {
stopNetworkMonitor()
super.onStop()
}
它的关系:
text
Lifecycle
↓
生命周期事件
↓
回调方法
↓
开发者执行逻辑
生命周期本身并不知道:
- 你启动了什么任务
- 任务什么时候结束
- 是否需要取消
- 资源什么时候释放
它只是告诉你:
"我现在发生了什么。"
这就是典型的事件驱动模型。
二、LifecycleObserver:把生命周期事件独立出来
随着业务复杂,直接把大量逻辑写在 Activity 中会越来越臃肿。
于是 AndroidX 引入了 Lifecycle。
生命周期逻辑可以独立:
kotlin
class NetworkObserver : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
startNetworkMonitor()
}
override fun onStop(owner: LifecycleOwner) {
stopNetworkMonitor()
}
}
架构变成:
text
LifecycleOwner
↓
Lifecycle
↓
LifecycleObserver
↓
onStart / onStop
相比以前:
text
Activity
|
|
大量生命周期代码
现在:
text
Activity
↓
LifecycleObserver
↓
业务逻辑
代码职责更加清晰。
但是:
LifecycleObserver 只是解决了代码组织问题,并没有改变事件驱动模型。
底层依然是:
text
生命周期变化
↓
事件通知
↓
调用回调
↓
执行逻辑
生命周期依然只是:
"告诉开发者发生了什么。"
三、传统 LifecycleObserver 模型:生命周期和数据传递是分开的
来看一个真实场景:
监听网络状态。
传统方式:
kotlin
class NetworkObserver(
context: Context,
private val onStatusChanged: (Boolean) -> Unit
) : DefaultLifecycleObserver {
private val connectivityManager =
context.getSystemService(
Context.CONNECTIVITY_SERVICE
) as ConnectivityManager
private val networkCallback =
object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
onStatusChanged(true)
}
override fun onLost(network: Network) {
onStatusChanged(false)
}
}
}
Activity 使用:
kotlin
class MainActivity : AppCompatActivity() {
private val observer =
NetworkObserver(this) { connected ->
if (connected) {
showOnline()
} else {
showOffline()
}
}
override fun onCreate(
savedInstanceState: Bundle?
) {
super.onCreate(savedInstanceState)
lifecycle.addObserver(observer)
}
}
看起来很自然。
但是分析整个链路:
text
LifecycleObserver
|
| 管理生命周期
↓
ConnectivityManager.NetworkCallback
|
| 产生数据
↓
onStatusChanged(Boolean)
|
| 回调通知
↓
Activity 更新 UI
这里其实存在两个完全不同的问题:
1. 生命周期管理
负责:
text
什么时候注册监听
什么时候取消监听
例如:
text
onStart()
onStop()
2. 数据传递
负责:
text
网络变化
↓
Boolean
↓
UI 更新
通过:
kotlin
onStatusChanged()
完成。
问题在于:
生命周期和数据流之间没有统一模型。
开发者需要自己维护:
text
生命周期
+
监听任务
+
回调关系
+
资源释放
四、传统回调模型的问题
当业务简单时:
text
NetworkObserver
↓
Activity
没有问题。
但是现代 App 往往存在:
text
网络状态
蓝牙状态
GPS状态
数据库变化
文件上传进度
WebSocket消息
于是代码逐渐变成:
text
NetworkObserver
↓
callback
↓
Activity
BluetoothObserver
↓
callback
↓
Activity
LocationObserver
↓
callback
↓
Activity
最终 Activity 里面充满:
kotlin
observer.setCallback {
}
observer.setCallback {
}
observer.setCallback {
}
开发者需要人工维护:
- 谁注册
- 谁取消
- 谁还活着
- 谁应该接收数据
- 页面销毁后是否还有回调
生命周期只负责:
text
开始
结束
但是任务和数据:
text
怎么启动
怎么取消
怎么传递
怎么释放
都需要自己管理。
五、协程:异步任务开始拥有自己的生命周期
现代 Android 最大变化来自 Kotlin 协程。
例如:
kotlin
lifecycleScope.launch {
loadData()
}
这里创建的不只是一个异步调用。
而是:
text
CoroutineScope
↓
Job
↓
Task
这个 Job 拥有自己的生命周期。
例如:
text
Activity
↓
Lifecycle
↓
CoroutineScope
↓
Job
↓
Network Request
当 Activity 销毁:
text
Lifecycle Destroy
↓
CoroutineScope cancel
↓
Job cancel
↓
任务结束
最大的变化:
异步任务第一次拥有了结构化的生命周期。
六、从事件通知,到任务边界
这是整个演进过程中最重要的变化。
传统:
text
Lifecycle
↓
START事件
↓
onStart()
↓
手动启动任务
现代:
text
Lifecycle
↓
Coroutine Scope
↓
Job
↓
Task
生命周期不再只是告诉你:
"发生了什么。"
而开始决定:
"这个任务是否应该存在。"
七、结构化并发:任务形成层级关系
协程进一步带来了结构化并发。
例如:
kotlin
lifecycleScope.launch {
launch {
loadUser()
}
launch {
loadMessage()
}
launch {
loadNotification()
}
}
任务关系:
text
Parent Job
|
┌───────────┼───────────┐
↓ ↓ ↓
User Job Message Job Notification Job
父任务取消:
text
Parent Job
↓
Cancel
↓
Child Jobs
↓
全部取消
这和传统生命周期代码最大的区别:
以前:
text
开发者维护任务关系
现在:
text
结构表达任务关系
八、Flow:持续数据也进入生命周期模型
协程解决了任务生命周期。
但是现代应用还有大量持续数据:
例如:
text
网络在线
↓
网络离线
↓
重新在线
这种场景更适合:
kotlin
Flow<Boolean>
Flow 表达:
一个持续产生数据的数据源。
例如:
kotlin
fun observeNetwork(): Flow<Boolean> =
callbackFlow {
val callback =
object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network)
trySend(true)
}
override fun onLost(network: Network) {
trySend(false)
}
}
connectivityManager.registerNetworkCallback(
request,
callback
)
awaitClose {
connectivityManager.unregisterNetworkCallback(
callback
)
}
}
此时模型变化:
以前:
text
NetworkCallback
↓
callback(Boolean)
↓
Activity
现在:
text
NetworkCallback
↓
Flow
↓
Coroutine
↓
UI
数据成为独立的数据流。
九、生命周期开始约束 Flow 和任务
现代 Android:
kotlin
repeatOnLifecycle(
Lifecycle.State.STARTED
) {
networkFlow.collect {
render(it)
}
}
这里生命周期的角色已经变化。
以前:
text
Lifecycle
告诉我:
onStart
onStop
现在:
text
Lifecycle
决定:
任务什么时候应该存在
当页面不可见:
text
Lifecycle
↓
Coroutine Cancel
↓
Flow停止收集
↓
awaitClose释放资源
完整链路:
text
Lifecycle
↓
Coroutine Scope
↓
Job
↓
Flow
↓
Data Source
↓
Resource Release
形成闭环。
十、两种模型真正的区别
回头看:
传统模型
text
Lifecycle
↓
Event
↓
Observer
↓
Callback
↓
开发者管理任务
关注:
发生了什么?
现代模型
text
Lifecycle
↓
State
↓
Coroutine Scope
↓
Structured Concurrency
↓
Flow
↓
Cancellation
关注:
当前生命周期下,哪些任务应该存在?
十一、生命周期角色的变化
因此 Android 生命周期的价值已经发生变化。
过去:
生命周期是事件通知器。
现在:
生命周期是异步任务的边界管理者。
可以简单总结:
第一阶段:事件驱动
text
Lifecycle
↓
Event
↓
Callback
关注:
发生了什么。
第二阶段:生命周期观察
text
Lifecycle
↓
Observer
↓
onStart/onStop
关注:
生命周期变化时我要做什么。
第三阶段:生命周期约束下的结构化任务
text
Lifecycle
↓
State
↓
Coroutine
↓
Job
↓
Flow
↓
Cancellation
关注:
当前状态下任务应该存在多久。
十二、总结
Android 生命周期的演进,表面看是 API 的变化。
但本质是异步编程模型的变化。
过去:
text
Lifecycle
↓
事件
↓
Callback
↓
手动管理任务
现在:
text
Lifecycle
↓
状态约束
↓
Coroutine Scope
↓
Structured Concurrency
↓
Flow
↓
Cancellation
所以可以概括:
以前,生命周期告诉你"发生了什么";现在,生命周期开始决定"任务能存在多久"。
最终:
text
Lifecycle → 管边界
Coroutine → 管任务
Flow → 管数据
Cancellation → 管结束
真正的变化,不是少写了几个:
kotlin
onStart()
onStop()
而是:
Android 从"开发者监听生命周期事件并手动拼装异步逻辑",演进到"利用生命周期约束结构化管理任务、数据和资源"。