如何从任何地方(存储库等)获取 Flow 重要吗?
Does it matter how to get Flow from anywhere(repository, etc.)?
我的流量列表是这样的:
val list = repository.someFlowList()
有时我会这样做:
fun list() = repository.someFlowList()
在 Google Codelab 中,它是这样使用的:
val list: Flow<List<Something>>
get() = repository.someFlowList()
我知道什么是属性、getter、setter 和函数。但我只想知道一件事:在效率、性能等方面有什么区别吗?如果重要的话,我将该流用作 activity.
中的实时数据(仅使用 asLiveData() 方法)
在 Kotlin 中有一个 Backing Fields 的概念,这些字段仅在需要时用作 属性 的一部分以在内存中保存其值。
使用 getter 函数 get() = repository.someFlowList()
每次访问 属性 时都会评估主体,因为没有为其分配支持字段。而在 val list = repository.someFlowList()
的情况下,值在初始化期间进行评估并保存在支持字段中。 Getters & Setters 上的 Kotlin 文档也对此进行了解释。
TL;DR:您应该更喜欢现场支持的 属性 而不是计算的 属性,但结果是一样的。如果是 热流 ,在这种情况下,您应该使用字段支持 属性 以避免意外行为。
Flow API 有点声明性,这意味着当您创建 Flow 时,您只是在定义它的作用,这就是为什么它被称为 cold flow.收集流量时,您定义的计算仅 运行s。这意味着您可以根据需要在同一个实例上多次调用 collect
,它定义的计算每次都会从头开始 运行。每次作为计算 属性 或函数结果创建新 Flow 实例的唯一潜在影响是,您分配了相同 Flow 定义的更多实例。
冷流
检查这个简单的例子:
val flow = flow {
emit(0)
emit(1)
}
runBlocking {
val f1 = flow
f1.collect {
println("Flow ID: ${f1.hashCode()} - emits $it")
}
val f2 = flow
f2.collect {
println("Flow ID: ${f2.hashCode()} - emits $it")
}
}
这将打印:
Flow ID: 608188624 - emits 0
Flow ID: 608188624 - emits 1
Flow ID: 608188624 - emits 0
Flow ID: 608188624 - emits 1
你看到同一个 Flow 实例在收集时将 运行 Flow 发射,每次收集它。
如果您使用 getter (val flow get() = flow {...}
) 更改分配,则输出为:
Flow ID: 608188624 - emits 0
Flow ID: 608188624 - emits 1
Flow ID: 511833308 - emits 0
Flow ID: 511833308 - emits 1
看到结果是一样的,不同的是现在你有2个Flow实例。
热流
当 Flow 是 hot 时,也就是说,它甚至在收集器开始收集之前就有值,那么情况就不同了。一个StateFlow就是一个典型的hot Flow。看看这个:
val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
val flow = MutableStateFlow(0)
val job1 = scope.launch {
val f = flow
f.value = 1 // <-- note this
f.collect {
println("A: $it")
}
}
val job2 = scope.launch {
val f = flow
f.collect {
println("B: $it")
}
}
runBlocking {
job1.cancelAndJoin()
job2.cancelAndJoin()
}
输出为:
A: 1
B: 1
两个 Flow 集合都收到单个热 Flow 实例的最新值。
如果您更改为 val flow get() = MutableStateFlow(0)
,您将获得:
A: 1
B: 0
这次我们创建了一个不同的 StateFlow 实例,因此第二个收集器错过了我们之前在第一个 Flow 实例上所做的值更改。如果 属性 公开为 public,这是一个问题,因为 属性 的实现,无论是字段支持的还是计算的,都不应该与调用者相关。最终这可能会导致意外行为 - 错误。
我的流量列表是这样的:
val list = repository.someFlowList()
有时我会这样做:
fun list() = repository.someFlowList()
在 Google Codelab 中,它是这样使用的:
val list: Flow<List<Something>>
get() = repository.someFlowList()
我知道什么是属性、getter、setter 和函数。但我只想知道一件事:在效率、性能等方面有什么区别吗?如果重要的话,我将该流用作 activity.
中的实时数据(仅使用 asLiveData() 方法)在 Kotlin 中有一个 Backing Fields 的概念,这些字段仅在需要时用作 属性 的一部分以在内存中保存其值。
使用 getter 函数 get() = repository.someFlowList()
每次访问 属性 时都会评估主体,因为没有为其分配支持字段。而在 val list = repository.someFlowList()
的情况下,值在初始化期间进行评估并保存在支持字段中。 Getters & Setters 上的 Kotlin 文档也对此进行了解释。
TL;DR:您应该更喜欢现场支持的 属性 而不是计算的 属性,但结果是一样的。如果是 热流 ,在这种情况下,您应该使用字段支持 属性 以避免意外行为。
Flow API 有点声明性,这意味着当您创建 Flow 时,您只是在定义它的作用,这就是为什么它被称为 cold flow.收集流量时,您定义的计算仅 运行s。这意味着您可以根据需要在同一个实例上多次调用 collect
,它定义的计算每次都会从头开始 运行。每次作为计算 属性 或函数结果创建新 Flow 实例的唯一潜在影响是,您分配了相同 Flow 定义的更多实例。
冷流
检查这个简单的例子:
val flow = flow {
emit(0)
emit(1)
}
runBlocking {
val f1 = flow
f1.collect {
println("Flow ID: ${f1.hashCode()} - emits $it")
}
val f2 = flow
f2.collect {
println("Flow ID: ${f2.hashCode()} - emits $it")
}
}
这将打印:
Flow ID: 608188624 - emits 0
Flow ID: 608188624 - emits 1
Flow ID: 608188624 - emits 0
Flow ID: 608188624 - emits 1
你看到同一个 Flow 实例在收集时将 运行 Flow 发射,每次收集它。
如果您使用 getter (val flow get() = flow {...}
) 更改分配,则输出为:
Flow ID: 608188624 - emits 0
Flow ID: 608188624 - emits 1
Flow ID: 511833308 - emits 0
Flow ID: 511833308 - emits 1
看到结果是一样的,不同的是现在你有2个Flow实例。
热流
当 Flow 是 hot 时,也就是说,它甚至在收集器开始收集之前就有值,那么情况就不同了。一个StateFlow就是一个典型的hot Flow。看看这个:
val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
val flow = MutableStateFlow(0)
val job1 = scope.launch {
val f = flow
f.value = 1 // <-- note this
f.collect {
println("A: $it")
}
}
val job2 = scope.launch {
val f = flow
f.collect {
println("B: $it")
}
}
runBlocking {
job1.cancelAndJoin()
job2.cancelAndJoin()
}
输出为:
A: 1
B: 1
两个 Flow 集合都收到单个热 Flow 实例的最新值。
如果您更改为 val flow get() = MutableStateFlow(0)
,您将获得:
A: 1
B: 0
这次我们创建了一个不同的 StateFlow 实例,因此第二个收集器错过了我们之前在第一个 Flow 实例上所做的值更改。如果 属性 公开为 public,这是一个问题,因为 属性 的实现,无论是字段支持的还是计算的,都不应该与调用者相关。最终这可能会导致意外行为 - 错误。