将LiveData转换为StateFlow

3

Android,Kotlin

我在数据源类中有以下LiveData,我不能改变它为StateFlow,因此需要在我的viewModel中将其转换为StateFlow。

val trackingCatalogInitialLoadLiveData: LiveData<Pair<CatalogTracking, Int>> by lazy {
    instantSearchDataSourceLiveData.switchMap { instantSearchDataSource ->
        instantSearchDataSource.initialLoadLiveData
    }
}

在我的ViewModel中,我有以下内容,这就是我不确定将LiveData转换为StateFlow的正确方法:

 val trackingCatalogInitialLoadStateFlow: StateFlow<Pair<CatalogTracking, Int>> by lazy {
        instantSearchDataSourceFactory.trackingCatalogInitialLoadLiveData.asFlow()
            .stateIn(viewModelScope, SharingStarted.Lazily, Pair(CatalogTracking(), 0))
    }

然后在我的片段中,我只是收集结果。
coroutineScope.launch {
        mInstantSearchViewModel.trackingCatalogInitialLoadStateFlow.collect { trackingPair ->
           // code here
    }

这是否是将LiveData转换为StateFlow的最佳实践?有什么需要注意的地方吗?


2
我已经有一段时间没有做Android开发了,所以我不能确定在这方面的最佳实践。我只想提醒你在stateIn中小心使用SharingStarted.Lazily - 据我所知,它不会启动更新状态流的协程,直到在其上调用collect {}。这意味着如果您只访问stateFlow.value,它将永远停留在初始值上。当然,在这里似乎不是您的情况,因为您确实调用了collect,但如果您正在寻找一般陷阱,请记住这一点。 - Joffrey
2
你在问题中没有提到这一点,但是你需要小心收集任意协程作用域中的流,而不是使用viewLifecycle.lifecycleScope,以确保你不会泄漏视图或尝试在它们可能已经被销毁后更新视图。 - Tenfour04
1个回答

2
您不需要使用by lazyasFlow()stateIn()都创建了简单的包装器,因此在属性初始化程序中直接调用它们非常容易。
正如@Joffrey所说,如果您使用SharingStarted.Lazily,在流具有任何收集器之前检查流的value将错误地显示您提供的初始值。由于LiveData是热的,因此懒启动StateFlow并没有带来太多好处。传输LiveData值到StateFlow的基础协程执行了微不足道的工作。
如果您不需要检查value(在大多数情况下您可能不需要),那么将其保留为冷流应该是可以的。即使asFlow()生成的Flow是冷的,底层的LiveData仍然是热的,因此当流的收集器收集它时,它们将始终获得最新的值。主要的行为差异在于,如果数据源未为LiveData提供保证的初始值,则StateFlow使您有机会在等待LiveData发布其第一个值之前发出提供的默认值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接