repeatOnLifecycle(Lifecycle.State.STARTED) 超详细总结

3 阅读3分钟

一、它到底是干嘛的?

一句话:让 Flow 的收集(collect)只在页面可见时执行,页面不可见时自动取消,避免内存泄漏、浪费资源、后台回调导致崩溃。

它是 Android 官方 唯一推荐 的 Flow 收集方式,专门用来解决:

  • Flow 收集生命周期泄漏
  • 页面退到后台还在收到数据
  • 多次进入页面导致重复 collect
  • 生命周期安全问题

二、生命周期对应关系

你只需要记住两个最常用:

1. Lifecycle.State.STARTED

  • 页面 可见 时:开始 collect
  • 页面 不可见(按 Home、切到别的 App):自动取消收集
  • 页面 再次可见重新启动收集

2. Lifecycle.State.RESUMED

  • 页面 可交互、在前台 时才收集
  • 弹出对话框、分屏等半可见状态:不收集

三、最典型使用场景(全部覆盖)

场景 1:收集 StateFlow / Flow 更新 UI(最常用)

所有 UI 观察 ViewModel 数据,必须用它。

kotlin

lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.uiState.collect { state ->
            // 只在页面可见时执行
            updateUi(state)
        }
    }
}

为什么必须这样写?

  • 页面不可见 → collect 自动停
  • 页面回来 → 自动恢复
  • 不会泄漏
  • 不会后台更新 UI 导致崩溃

场景 2:一个页面收集多个 Flow

多个 Flow 都要生命周期安全,全部包在同一个 repeatOnLifecycle 里

kotlin

lifecycleScope.launch {
    repeatOnLifecycle(STARTED) {
        launch {
            viewModel.uiState.collect { ... }
        }
        launch {
            viewModel.eventFlow.collect { ... }
        }
    }
}

场景 3:列表、分页、搜索等持续数据流

例如:

  • Paging3
  • 搜索框实时搜索
  • 蓝牙 / 位置回调
  • 传感器数据

只要是 Flow 且要更新 UI,都必须用 repeatOnLifecycle(STARTED)

场景 4:防止 “页面关闭了还在执行”

比如:

  • 请求网络返回后更新 View
  • 定时器 Flow
  • 无限循环的 Flow

不用它,就会:

  • 内存泄漏
  • 崩溃
  • 耗电、耗流量

四、它和直接 lifecycleScope.launch 有什么区别?(重点)

错误写法(很多人踩坑)

kotlin

// ❌ 危险!页面销毁了还在收集,泄漏+崩溃
lifecycleScope.launch {
    viewModel.uiState.collect { ... }
}

问题:

  • lifecycleScope 只是在销毁时 最后取消
  • 但页面不可见时 仍然在运行
  • 后台收到数据 → 更新 UI → 崩溃

正确写法 ✅

kotlin

lifecycleScope.launch {
    repeatOnLifecycle(STARTED) {
        viewModel.uiState.collect { ... }
    }
}

行为:

  • 可见 → 运行
  • 不可见 → 停止
  • 再回来 → 重新开始
  • 销毁 → 彻底取消

五、repeatOnLifecycle 内部执行机制(超清晰)

plaintext

onStart()  →  进入 STARTED  →  开始执行代码块
onStop()   →  退出 STARTED  →  取消代码块(包括 collect)
再次onStart → 重新执行代码块

它会重复执行代码块,所以叫 repeatOnLifecycle

六、适用 vs 不适用场景

✅ 适用(必须用)

  • StateFlow 观察 UI 状态
  • SharedFlow 观察一次性事件
  • 网络请求 Flow
  • 数据库观察 Flow
  • 搜索、列表、分页数据流

❌ 不适用(不要用)

  • 只执行一次的请求(不 collect,直接 launch 就行)
  • 不需要生命周期控制的后台任务
  • 不需要随页面可见性启停的任务

七、repeatOnLifecycle 在compose中使用吗?

非常重要:Compose 里不使用 repeatOnLifecycle

我给你用最清晰、最不会错的方式讲清楚:

1、 结论先说
  • 在 XML 视图(Fragment/Activity)
    • ✅ 使用:repeatOnLifecycle(STARTED)


  • 在 Jetpack Compose 视图
    • ❌ 不使用 repeatOnLifecycle
    • ✅ 取而代之使用:collectAsStateWithLifecycle
2、为什么 Compose 不用 repeatOnLifecycle?

因为:

  1. repeatOnLifecycle 是给 命令式 XML 用的
  2. Compose 是 声明式 UI,自带重组、生命周期感知
  3. collectAsStateWithLifecycle() 是官方专门为 Compose 打造的
  4. 它内部自动处理:STARTED/STOPPED 生命周期,比手动写更安全
3、 官方最新标准(必须用)

kotlin

val uiState by viewModel.uiState.collectAsStateWithLifecycle()

八、完整 Compose 示例(直接复制)

ViewModel

kotlin

class MyViewModel : ViewModel() {
    private val _uiState = MutableStateFlow(UiState())
    val uiState: StateFlow<UiState> = _uiState.asStateFlow()
}

Compose UI

kotlin

@Composable
fun HomeScreen(viewModel: MyViewModel = viewModel()) {
    // ✅ 生命周期安全收集
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()

    Column {
        if (uiState.isLoading) {
            CircularProgressIndicator()
        }
        Text(uiState.data ?: "无数据")
    }
}