Jetpack Compose 中安全地消耗Flow
以 Lifecycle 为周期的方式收集流是在 Android 上收集流的推荐方式。如果您正在使用 Jetpack Compose 构建 Android 应用程序,则使用 collectAsStateWithLifecycle
API 可以在 Lifecycle 为周期的方式下从您的 UI 中收集流。
collectAsStateWithLifecycle
允许您的应用程序在不需要时保存应用程序资源,例如当应用程序在后台时。保持不必要的资源活动可能会影响用户的设备健康状况。这些资源可能包括 Firebase 查询、位置或网络更新以及数据库连接等。
继续阅读了解有关此 API 的更多信息,以及为什么应该以 Lifecycle 为周期的方式进行收集,以及它与 collectAsState
API 的比较。
collectAsStateWithLifecycle
collectAsStateWithLifecycle
是一种可组合的函数,可按 Lifecycle 的方式从流中收集值,并将最新值表示为 Compose State。每次发生新的流发射时,此 State 对象的值都会更新。这会导致重组成中的每个 State.value使用。
默认情况下,collectAsStateWithLifecycle
使用 Lifecycle.State.STARTED
来启动和停止从流中收集值。这发生在 Lifecycle 移动到目标状态时的进入和退出之间。这是您可以在 minActiveState
参数中配置的 Lifecycle 状态。
以下片段演示了如何使用collectAsStateWithLifecycle
来收集ViewModel在组合函数中公开的StateFlow的uiState
字段:
/* Copyright 2022 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
@OptIn(ExperimentalLifecycleComposeApi::class)
@Composable
fun AuthorRoute(
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
viewModel: AuthorViewModel = hiltViewModel()
) {
val uiState: AuthorScreenUiState by viewModel.uiState.collectAsStateWithLifecycle()
AuthorScreen(
authorState = uiState.authorState,
newsState = uiState.newsState,
modifier = modifier,
onBackClick = onBackClick,
onFollowClick = viewModel::followAuthorToggle,
)
}
每当AuthorViewModel
的uiState
发出新的AuthorScreenUiState
值时,AuthorRoute
都会重新组合。有关collectAsStateWithLifecycle
的更多用法,请查看Android应用程序中的Now以及其迁移PR。
要开始在项目中使用collectAsStateWithLifecycle
API,请将androidx.lifecycle.lifecycle-runtime-compose构件添加到项目中。
// app/build.gradle file
dependencies {
implementation "androidx.lifecycle:lifecycle-runtime-compose:2.6.0"
}
在幕后
在幕后,collectAsStateWithLifecycle
的实现使用repeatOnLifecycle
API,这是使用View系统在Android中收集流的推荐方式。
collectAsStateWithLifecycle
可以使你免于编写下面显示的样板代码,该代码也以受生命周期影响的方式从可组合函数中收集流量。
架构中的流式集合
应用程序构架中的类型不应了解其他类型的实现细节。UI 不应该知道 ViewModel 如何生成 UI 状态。如果 UI 在屏幕上不可见,则流式集合应该停止以释放应用程序资源(如果合适)。
UI 可以通过使用 collectAsStateWithLifecycle
收集 UI 状态来帮助释放资源。视图模型可以通过以收集器感知的方式生成 UI 状态来实现相同的功能。如果没有收集器,例如当 UI 在屏幕上不可见时,可以通过在生成 UI 状态时使用.stateIn(WhileSubscribed)
流 API 停止来自数据层的上游流。有关此内容的更多信息,请观看“ Kotlin 流实践”系列讲座中的该部分。要测试以此方式生成 UI 状态的视图模型,请查看测试指南。
流的消费者和生产者不需要知道彼此的实现方式。在具有多个环境、变体、库和功能的大型应用程序中找出实现细节可能非常耗时。更糟糕的是,维护依赖于实现细节的代码很困难。
保持后台资源处于活动状态
Android 应用程序可以在众多 Android 设备上运行。不幸的是,并非所有设备和用户都拥有无尽的资源。应用程序通常在受限环境中运行。当 Android 应用程序运行时,有一些重要因素会影响用户体验和设备系统健康:
- CPU 使用率:CPU 是所有设备组件中电池消耗最高的。电池寿命是永恒的用户关注点。如果被滥用,用户可能会卸载您的应用程序。
- 数据使用量:在应用程序未连接到 Wi-Fi 时减少网络流量可以帮助用户节省金钱。
- 内存使用率:应用程序如何使用内存可以对设备的整体稳定性和性能产生非常大的影响。
想要尊重用户、设备系统健康或面向亿万用户的 Android 开发人员应根据市场、设备或国家/地区的情况优化这些不同因素。保持不需要的资源处于活动状态可能对所使用的设备和设备运行的 Android 版本类型产生负面影响。在 UI 层中使用collectAsStateWithLifecycle
可以使层次结构的其余部分释放资源。
collectAsState
对比
开发人员经常会问:如果 collectAsStateWithLifecycle
是从 Android 的 composable 函数中收集 flow 的最安全方式,我们为什么现在还需要 collectAsState
API 呢? 或者为什么不将生命周期感知功能添加到 collectAsState
中,而是要创建一个新的 API?
composable 函数的生命周期与运行 Compose 的平台无关。如《composables 生命周期》页面所述,composable 函数的实例进入 Composition、重新计算 0 或多次,最后离开 Composition。
collectAsState
API 遵循组合的生命周期。它在可组合函数进入组合时开始收集流,离开组合时停止收集。collectAsState
是跨平台的 API,可用于收集流。
但是,在 Android 应用程序中使用 Compose 时,Android 生命周期也在如何管理资源方面发挥着至关重要的作用。即使在 Android 应用程序处于后台状态时,Compose 停止重新组合,collectAsState
仍保持收集活动。这使得层次结构中的其余部分无法释放资源。
在 Compose 中,collectAsState 和 collectAsStateWithLifecycle 都有其目的。当开发 Android 应用程序时使用后者,当开发其他平台时使用前者。
从 collectAsState
迁移到 collectAsStateWithLifecycle
是易如反掌的:
/* Copyright 2022 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
@Composable
fun AuthorRoute(
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
viewModel: AuthorViewModel = hiltViewModel()
) {
- val uiState: AuthorScreenUiState by viewModel.uiState.collectAsState()
+ val uiState: AuthorScreenUiState by viewModel.uiState.collectAsStateWithLifecycle()
AuthorScreen(
authorState = uiState.authorState,
newsState = uiState.newsState,
modifier = modifier,
onBackClick = onBackClick,
onFollowClick = viewModel::followAuthorToggle,
)
}
以生命周期感知方式收集流是在Android上收集流的推荐方法,以便允许应用程序中的其他部分在需要时释放资源。
如果您正在使用Jetpack Compose构建Android应用程序,请使用collectAsStateWithLifecycle
合成功能执行此操作。
参考
https://github.com/android/nowinandroid
https://developer.android.com/topic/architecture/ui-layer#consume-ui-state