Lifecycle - 生命周期
Lifecycle 库提供了一组类和接口,用于构建感知生命周期的组件。这些组件可以根据 Activity 或 Fragment 的当前生命周期状态自动调整其行为。
引入依赖
在大规模项目中,建议使用 Version Catalog 管理版本。
[versions]
lifecycle = "2.8.0"
[libraries]
# 核心库 (Lifecycle, ViewModel, LiveData)
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" }
androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycle" }dependencies {
implementation(libs.androidx.lifecycle.runtime.ktx)
// 如果需要 Java 8 支持 (DefaultLifecycleObserver)
implementation("androidx.lifecycle:lifecycle-common-java8:${libs.versions.lifecycle.get()}")
}前言:为什么需要 Lifecycle?
在没有 Lifecycle 库之前,我们通常需要在 Activity 或 Fragment 的生命周期方法中手动管理组件。
比如,有一个定位相关的功能,它依赖于 Activity 的生命周期:当 Activity 处于 onStart 时开始定位,当 onStop 时停止定位。传统的写法可能是这样的:
class MyLocationListener(
private val context: Context,
) {
fun start() {
// 开启定位
}
fun stop() {
// 停止定位
}
}
class MyActivity : AppCompatActivity() {
private lateinit var myLocationListener: MyLocationListener
override fun onCreate(...) {
myLocationListener = MyLocationListener(this)
}
public override fun onStart(...) {
super.onStart()
myLocationListener.start()
}
public override fun onStop(...) {
super.onStop()
myLocationListener.stop()
}
}这种模式存在显著的问题:
- 代码臃肿与耦合:随着功能的增加(如视频播放器、数据下载、分析埋点等),Activity 的
onStart和onStop等方法会充斥着大量的调用代码,难以维护。 - 生命周期竞争条件:如果组件的初始化是异步的,可能出现
onStop在组件完全启动前就被调用的情况。这会导致组件在应该停止时仍在运行,从而引发内存泄漏或崩溃。
Lifecycle 库通过将生命周期管理的职责转移给组件本身,优雅地解决了这些问题。
核心概念
Lifecycle
Lifecycle 是一个类,它持有关于组件(如 Activity 或 Fragment)生命周期状态的信息,并允许其他对象观察这些状态。
它使用两个主要枚举来跟踪生命周期状态:
- Event (事件):从框架和
Lifecycle类分派的生命周期事件。它们直接映射到 Activity 和 Fragment 中的回调事件(如ON_CREATE,ON_START,ON_RESUME等)。 - State (状态):
Lifecycle对象跟踪的组件的当前状态(如INITIALIZED,DESTROYED,CREATED,STARTED,RESUMED)。
(图源:Android Developers)
你可以将状态看作是图中的节点,将事件看作是节点之间的边。
LifecycleOwner
LifecycleOwner 是一个单一方法接口,表示类具有 Lifecycle。
public interface LifecycleOwner {
public val lifecycle: Lifecycle
}- 谁实现了它?
AppCompatActivity,Fragment,ComponentActivity等 Android 核心组件都已经实现了这个接口。 - 有什么用? 它允许观察者将自己与拥有生命周期的对象关联起来,而无需直接依赖于 Activity 或 Fragment 的具体子类。
LifecycleObserver
LifecycleObserver 是观察者接口。你可以通过实现 DefaultLifecycleObserver 接口来处理生命周期事件。
class MyObserver : DefaultLifecycleObserver {
override fun onCreate(owner: LifecycleOwner) {
// 连接到服务、初始化资源等
}
override fun onResume(owner: LifecycleOwner) {
// 开始播放、恢复数据流等
}
override fun onPause(owner: LifecycleOwner) {
// 暂停播放、停止数据流等
}
// ... 其他生命周期方法
}注意:旧版 API 中使用的
@OnLifecycleEvent注解已被废弃,建议使用DefaultLifecycleObserver。
基本用法
创建观察者
将依赖生命周期的逻辑封装在观察者类中。
class MyLocationListener(
private val context: Context,
private val lifecycle: Lifecycle
) : DefaultLifecycleObserver {
init {
// 在初始化时自动添加自己为观察者
lifecycle.addObserver(this)
}
override fun onStart(owner: LifecycleOwner) {
if (enabled) {
// 连接定位服务
}
}
fun enable() {
enabled = true
if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
// 如果当前已经在 STARTED 状态,立即连接
// 连接定位服务
}
}
override fun onStop(owner: LifecycleOwner) {
// 断开定位服务
}
}在 Activity/Fragment 中使用
Activity 的代码变得极其简洁:
class MyActivity : AppCompatActivity() {
private lateinit var myLocationListener: MyLocationListener
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 只需实例化,观察者会自动 hook 生命周期
myLocationListener = MyLocationListener(this, lifecycle)
}
}进阶:Lifecycle 与协程 (Coroutines)
在现代 Android 开发中,我们经常结合 Kotlin 协程使用。Lifecycle KTX 扩展库提供了与 Lifecycle 绑定的协程作用域。
lifecycleScope
为每个 Lifecycle 对象定义了 LifecycleScope。在此范围内启动的协程会在 Lifecycle 被销毁时自动取消。
import androidx.lifecycle.lifecycleScope
class MyFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch {
// 这个协程会在 Fragment 的 View 被销毁时自动取消
// updateUI()
}
}
}repeatOnLifecycle (推荐)
这是收集 Flow 的推荐方式。它会在生命周期至少处于特定状态(通常是 STARTED)时启动协程块,并在低于该状态时取消协程块。这对于 UI 更新非常关键,可以避免在后台浪费资源或导致崩溃。
import androidx.lifecycle.repeatOnLifecycle
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 使用 lifecycleScope 启动协程
lifecycleScope.launch {
// repeatOnLifecycle 会挂起调用它的协程,直到 Lifecycle 被销毁
// 当生命周期处于 STARTED 状态时,执行 block 中的代码
// 当生命周期变为 STOPPED 时,取消 block 中的代码
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { uiState ->
// 更新 UI
}
}
}
}
}Fragment 中的两个生命周期
Fragment 有一个特殊的点:它有两个生命周期。
- Fragment 自身的生命周期 (
lifecycle):对应 Fragment 对象的创建和销毁。 - Fragment View 的生命周期 (
viewLifecycleOwner.lifecycle):对应 Fragment 视图的创建和销毁。
最佳实践:在 onViewCreated 中观察 LiveData 或收集 Flow 时,务必使用 viewLifecycleOwner。
这是因为 Fragment 的 View 可能会被销毁(例如放在 BackStack 中),但 Fragment 实例本身仍然存在。如果使用 lifecycle,观察者就不会被移除,导致视图重建时产生重复的观察者,引发 Bug。
// 正确做法
viewModel.someData.observe(viewLifecycleOwner) { /* ... */ }
// 错误做法 (在 Fragment 中操作 UI 时)
viewModel.someData.observe(this) { /* ... */ }自定义 LifecycleOwner
如果你想让非 Activity/Fragment 的类也拥有生命周期(例如自定义 View 或 Service),可以实现 LifecycleOwner 接口并使用 LifecycleRegistry。
class MyService : Service(), LifecycleOwner {
private val lifecycleRegistry = LifecycleRegistry(this)
override val lifecycle: Lifecycle
get() = lifecycleRegistry
override fun onCreate() {
super.onCreate()
lifecycleRegistry.currentState = Lifecycle.State.CREATED
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
lifecycleRegistry.currentState = Lifecycle.State.STARTED
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
}
}总结
使用生命周期感知型组件的最佳实践:
- 保持 UI 控制器(Activity/Fragment)精简:它们不应包含复杂的业务逻辑,只负责 UI 和系统的交互。
- 使用 ViewModel:将数据和业务逻辑放在 ViewModel 中,UI 控制器只负责观察数据。
- 使用 Data Binding / View Binding:减少 findViewById 和手动更新 View 的代码。
- 总是处理 onStop/onPause:如果你的组件在
onStart/onResume中启动了某些操作,务必确保在对应的onStop/onPause中能够正确停止,避免内存泄漏。 - 使用
repeatOnLifecycle:在 UI 层安全地收集 Flow 数据。