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