所以我有一个具体的问题。
我们已经开始重构遗留代码,此时,我们需要采用遗留类。
因此遗留类会执行一些网络调用,并根据响应设置一些 liveData 对象。
在该功能中,它将被重构,而不是 liveData ,它将在挂起乐趣中执行所有操作并返回相应的数据,但现在我们无法使用这种方法。
所以我正在考虑某种混合解决方案。
我想在一个流程中收集所有这些实时数据,这将是一个用例。理论上只会发生一次发射,因为只有一个 liveData 会获得值。
在 viewModel 中,我订阅它并执行所有操作。第一次收集后我想销毁这个收集工作。也许我可以在流程中使用 takeWhile() 运算符。
好不好?会不会造成内存泄漏? takeWhile 将会
这就是现在的样子:
class UseCase(){
operator fun invoke(a: LiveData<String>, b: LiveData<String>, c: LiveData<Int>) =
flow<Result<String>> {
a.asFlow().collect{
emit(Resource.Error)
}
b.asFlow().collect{
emit(Resource.Error)
}
c.asFlow().collect{
emit(Resource.Success)
}
}
}
class TestViewModel(): ViewModel(){
fun getData(){
var shouldCollect = true
viewModelScope.launch {
UseCase().invoke(MutableLiveData(""),MutableLiveData(""),MutableLiveData(1)).takeWhile { shouldCollect }.collect{
shouldCollect = false
}
}
}
}
我知道这不是一个好方法,但是一旦依赖类被重构,它就会被替换。
所以现在我尝试了一下,但行不通。只有列表中的第一个 liveData 会更新流程,因此如果第二个 liveData 获取值,它会由于某种原因不会发出它。我尝试合并/压缩/组合它们
我不完全确定你想用它做什么,但你可以
merge
将同一类型的多个流合并到一个流中:
operator fun invoke(
a: LiveData<String>,
b: LiveData<String>,
c: LiveData<Int>,
): Flow<Result<String>> = merge(
a.asFlow().map { Resource.Error },
b.asFlow().map { Resource.Error },
c.asFlow().map { Resource.Success },
)
这将发出至少 3 个值,但不保证发出元素的顺序。
如果您想将流的值
combine
改为单个值,可以这样做:
operator fun invoke(
a: LiveData<String>,
b: LiveData<String>,
c: LiveData<Int>,
): Flow<Result<String>> = combine(
a.asFlow(),
b.asFlow(),
c.asFlow(),
) { valueA, valueB, valueC ->
if (...) {
Resource.Success
} else {
Resource.Error
}
}
我也不确定你想在视图模型中实现什么目标。如果底层 LiveData 不再改变,那么仍然收集流量也没有什么坏处;无论如何,什么也不会发生。如果您只对第一个值感兴趣,并且想忽略之后的任何更改,您可以使用与您的方法类似的方法,但我不确定这在您的场景中有多强大:每次调用
getData()
时重新创建流,您可以有效地获取 LiveDatas 的当前值,而不是开始时的值。
但话又说回来,您甚至不应该在视图模型中收集流。总体思路是在尽可能最低的级别(在数据层中)生成流,并在 UI 中尽可能最新的时刻收集流。介于两者之间的所有内容,包括您的视图模型,都应该只转换流(如上面的 merge
和
combine
)。视图模型作为收集之前的最后一行,应该将所有流转换为 ui 状态对象流,并使其成为
StateFlow
,其中:
stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = /* some initial value to use until the flows produce their first value */,
)
如果您为 UI 使用 compose 并使用 collectAsStateWithLifecycle
收集结果流,则效果特别好。