Jetpack?lifecycle!!!

前言

平时写页面的时候,经常要在onStart开启轮询、定位、动画,再去onStop停止。所有逻辑写在 Activity/Fragment 里,代码臃肿,还很容易忘记释放资源引发内存泄漏。

Lifecycle 是 Jetpack 的基础组件,作用就是让普通类感知页面生命周期,把和生命周期绑定的业务逻辑抽离出去,实现解耦。

依赖引入

复制代码
dependencies {
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.8.4"
}

核心概念

Lifecycle 基于观察者模式,三个核心角色:

  1. LifecycleOwner :生命周期持有者,拥有 lifecycle 对象。AppCompatActivity、Fragment 都实现了这个接口;Fragment 操作 View 相关逻辑要用 viewLifecycleOwner。
  2. Lifecycle:状态机,保存当前状态,分发生命周期事件。
  3. 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 内部感知宿主生命周期,不用业务手动释放

避坑总结

  1. Fragment UI 逻辑使用 viewLifecycleOwner,不要直接用 fragment.lifecycle,二者生命周期不同;
  2. Lifecycle 只会分发回调,不会自动帮你取消任务、关闭线程,释放资源代码需要自己写;
  3. 一个 Observer 不要同时 add 给多个 LifecycleOwner;
  4. 配置变更(屏幕旋转)Activity 会重建,Lifecycle 会走完整销毁重建;长任务搭配 ViewModel;

和其他组件的关系

  • Lifecycle:感知生命周期,分发状态事件
  • ViewModel:独立于页面生命周期,屏幕旋转不销毁
  • LiveData:自带 Lifecycle 感知,只有活跃状态的观察者接收数据回调

小结

Lifecycle 的核心就是解耦。把绑定生命周期的业务从 Activity/Fragment 剥离为独立可复用类,代码更清爽,减少内存泄漏,也是 LiveData、Navigation 等 Jetpack 组件的底层基石。

相关推荐
松仔log7 小时前
Kotlin中级——callbackFlow
java·前端·kotlin
zh_xuan7 小时前
kotlin常见面试题
开发语言·kotlin·面试题
mmsx7 小时前
耳切法切带洞多边形:论文能跑通,真实数据为什么崩
android·kotlin
洞见前行7 小时前
你的 Activity 关了,为什么还活着?Android 内存泄漏从发现、定位到线上治理
android·性能优化·leakcanary
Kapaseker9 小时前
Kotlin 又要加语法糖了:这次轮到 if-else
android·kotlin
恋猫de小郭11 小时前
Flutter 3.50 & Dart 3.14 发布,快来看看有什么更新吧
android·前端·flutter
Starry-sky(jing)1 天前
Vidda ADB 开启:R Pro 65 找不到开发者选项的处理与连接验收
android·adb·远程控制·电视·vidda
雨白1 天前
从原理到实践:使用 Kotlin KSP 仿写 ButterKnifeLite
android·kotlin