Home API 的 Kotlin 版本使用 flow,这是 Kotlin 语言的一项功能,可提供强大的功能来处理异步数据流,包括转换、过滤、映射、转换为集合和从集合转换等。
协程与流程密切相关,可为编写异步代码提供优雅的抽象,让开发者无需显式编写回调例程。流与协程密切配合,可用于异步从协程检索数据,而无需等待函数或线程完成。
使用方通过称为“收集”的过程从数据流中检索数据。Kotlin Flow 有一个 collect()
函数,可用于此目的。在收集期间,流程中会发生什么取决于流程的类型。
Kotlin Flow (Flow<T>
) 默认处于冷态,这意味着只有在调用 collect()
时,流构建器代码才会生成数据。与之相反,热流会立即生成数据,并将其缓冲在内存中,就像队列一样,以便在有数据被使用时使用。由于热流会在内存中维护数据,因此被视为有状态的。
您可以使用 shareIn
运算符将冷数据流转换为热数据流(请参阅利用 shareIn
使冷数据流变为热数据流)。您还可以使用 SharedFlow
或 StateFlow
将冷数据流转换为热数据流。
示例应用如何使用数据流
示例应用使用 Jetpack Compose 中的视图模型,这些视图模型连接到 Home API 中的流程。许多示例应用界面元素由状态驱动,但可以与之互动。该示例应用还会将来自设备的状态与界面中的“乐观”状态混合,以提供实时用户体验。“乐观”一词表示应用假定给定操作已成功,并立即更新界面以反映预期结果,而无需等待确认。如果操作失败,界面会更新以反映真实状态。
在示例应用中,系统会为视图模型的每个层(结构、房间、设备)创建流程。例如,它会在 GlobalViewModel.kt
中通过以下调用对结构执行此操作:
fun getStructuresState(): StateFlow<List<StructureModel>?> =
homeClient
.structures()
.map { structures -> structures.map { StructureModel(it.name, it) }.sortedBy { it.name } }
.handleErrors()
.flowOn(Dispatchers.IO)
.stateIn(scope = viewModelScope, started = SharingStarted.WhileSubscribed(), null)
emitAll()
会从给定流收集所有值,并将其发送到收集器。stateIn()
会与多个下游订阅方共享来自上游流的单个正在运行实例的最新发射值。如需了解详情,请参阅 kotlinx.coroutines.flow
参考文档。
Jetpack Compose
如需在本地内存中存储流对象并防止其终止,请使用 Kotlin remember
API。
在 Jetpack Compose 中,如果您将此方法与 collectAsStateWithLifecycle()
搭配使用,Jetpack 会根据显示该状态的应用界面是否实际位于前台来自动管理对数据流的订阅和取消订阅。
示例应用中的一个简单调用即可实现此目的。使用前面所示的 getStructuresState()
函数:
val structuresList by
remember(globalViewModel) { globalViewModel.getStructuresState() }.collectAsStateWithLifecycle()
现在,当结构的任何状态发生变化(例如 name
)时,使用该结构的可组合函数将自动反映更新后的状态。在示例应用中,这是 HomeActivityContent()
函数。
资源
如需详细了解 Kotlin、数据流、协程和 Jetpack Compose,请参阅以下资源:
- 使用 Kotlin 开发 Android 应用
- 了解适用于 Android 的 Kotlin
- Android 上的 Kotlin 协程。以下特定 Codelab 可能对您有所帮助:
- Android 上的 Kotlin 数据流,更具体地说,是 StateFlow。
- 状态和 Jetpack Compose,尤其是
collectAsStateWithLifecycle()
函数。此函数会根据显示该状态的界面是否实际位于前台,自动管理对数据流的订阅和取消订阅。 - 如果您使用的是 Automation API,不妨阅读 Kotlin 类型安全构建器,以便了解 Automation DSL 的运作方式。