前言
平时写页面的时候,经常要在onStart开启轮询、定位、动画,再去onStop停止。所有逻辑写在 Activity/Fragment 里,代码臃肿,还很容易忘记释放资源引发内存泄漏。
Lifecycle 是 Jetpack 的基础组件,作用就是让普通类感知页面生命周期,把和生命周期绑定的业务逻辑抽离出去,实现解耦。
依赖引入
dependencies {
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.8.4"
}
核心概念
Lifecycle 基于观察者模式,三个核心角色:
- LifecycleOwner :生命周期持有者,拥有
lifecycle对象。AppCompatActivity、Fragment都实现了这个接口;Fragment 操作 View 相关逻辑要用viewLifecycleOwner。 - Lifecycle:状态机,保存当前状态,分发生命周期事件。
- LifecycleObserver :观察者,接收生命周期回调。
DefaultLifecycleObserver:推荐使用,直接重写对应生命周期方法LifecycleEventObserver:接收原始 Event 事件,自己判断处理
状态流转: INITIALIZED → CREATED → STARTED → RESUMED → DESTROYED
事件: ON_CREATE、ON_START、ON_RESUME、ON_PAUSE、ON_STOP、ON_DESTROY
示例 1:DefaultLifecycleObserver
写一个轮询工具类,页面可见自动开启,不可见自动停止:
class PollingManager : DefaultLifecycleObserver {
private val handler = android.os.Handler(android.os.Looper.getMainLooper())
private var runnable: Runnable? = null
override fun onStart(owner: LifecycleOwner) {
super.onStart(owner)
startPoll()
}
override fun onStop(owner: LifecycleOwner) {
super.onStop(owner)
stopPoll()
}
private fun startPoll() {
runnable = Runnable {
println("轮询执行...")
handler.postDelayed(runnable!!, 2000)
}
handler.post(runnable!!)
}
private fun stopPoll() {
runnable?.let { handler.removeCallbacks(it) }
}
}
在 Activity 中注册:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
lifecycle.addObserver(PollingManager())
}
}
Fragment 中,和 View 相关的监听一定要用viewLifecycleOwner:
viewLifecycleOwner.lifecycle.addObserver(PollingManager())
示例 2:LifecycleEventObserver 接收原始事件
适合需要统一处理多个生命周期事件的场景:
class LifecycleLogObserver : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
when (event) {
Lifecycle.Event.ON_CREATE -> println("ON_CREATE")
Lifecycle.Event.ON_START -> println("ON_START")
Lifecycle.Event.ON_RESUME -> println("ON_RESUME")
Lifecycle.Event.ON_PAUSE -> println("ON_PAUSE")
Lifecycle.Event.ON_STOP -> println("ON_STOP")
Lifecycle.Event.ON_DESTROY -> println("ON_DESTROY")
else -> {}
}
}
}
注册方式一样:
lifecycle.addObserver(LifecycleLogObserver())
示例 3:ProcessLifecycleOwner 监听 App 前后台
监听整个 App 的前台、后台状态,全局使用:
ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
super.onStart(owner)
println("App 进入前台")
}
override fun onStop(owner: LifecycleOwner) {
super.onStop(owner)
println("App 退到后台")
}
})
注意:
onStart= App 至少有一个页面可见;onStop= 所有页面全部不可见。
搭配协程:lifecycleScope + repeatOnLifecycle
lifecycle-ktx 提供的协程扩展,底层依赖 Lifecycle,页面销毁自动取消协程,不会泄漏:
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
// 页面处于 STARTED 状态时运行,PAUSE 自动挂起,DESTROY 自动取消
}
}
Fragment 同样优先用 viewLifecycleOwner:
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
}
}
适用场景
- 定时轮询、WebSocket、蓝牙、传感器、定位
- 动画、播放器:页面可见播放,不可见暂停
- 页面埋点统计,逻辑抽离
- SDK 内部感知宿主生命周期,不用业务手动释放
避坑总结
- Fragment UI 逻辑使用
viewLifecycleOwner,不要直接用 fragment.lifecycle,二者生命周期不同; - Lifecycle 只会分发回调,不会自动帮你取消任务、关闭线程,释放资源代码需要自己写;
- 一个 Observer 不要同时 add 给多个 LifecycleOwner;
- 配置变更(屏幕旋转)Activity 会重建,Lifecycle 会走完整销毁重建;长任务搭配 ViewModel;
和其他组件的关系
- Lifecycle:感知生命周期,分发状态事件
- ViewModel:独立于页面生命周期,屏幕旋转不销毁
- LiveData:自带 Lifecycle 感知,只有活跃状态的观察者接收数据回调
小结
Lifecycle 的核心就是解耦。把绑定生命周期的业务从 Activity/Fragment 剥离为独立可复用类,代码更清爽,减少内存泄漏,也是 LiveData、Navigation 等 Jetpack 组件的底层基石。