在 ViewModel 中收集流

问题描述 投票:0回答:1

我正在使用 Compose 和 Room 数据库编写一个 Android 应用程序。我有一个可行的解决方案,但我不确定我是否使用了最佳实践。我在 ViewModel 的 init 中收集两个流,以便我可以创建在 ViewModel 的可组合项中使用的 UI 状态:

class MyViewModel(
   savedStateHandle: SavedStateHandle,
   context: Context
) : ViewModel() {

   // Some code omitted

   var uiState by mutableStateOf(MyUiState())

   init {
      viewModelScope.launch {
         combine(
            myRepo.getMovie(movieId).filterNotNull(),
            myRepo.getActors(movieId)
         ) { movie, actors ->
            uiState.copy(
               movie = movie,
               actorList = actors
            )
         }.collect { newState ->
            uiState = newState
         }
      }
   }
}

根据我的研究,在 init 中调用collect()可能是有问题的,但我很难找到任何硬文档说不要这样做。而且我不知道任何其他方法可以在添加或删除演员时自动更新 uiState 而无需调用collect()。任何有关更新 uiState 的更好解决方案的建议将不胜感激。

android-jetpack-compose android-viewmodel
1个回答
0
投票

总体思路是仅转换视图模型中的流,收集只能在 UI 中完成。这样,UI 可以根据需要订阅和取消订阅流,从而节省资源。

在您的示例中,

uiState
应该是一个流,具体来说,它应该是一个
StateFlow

val uiState: StateFlow<MyUiState> = transformedFlow(movieId)
    .stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5_000),
        initialValue = MyUiState(),
    )

Kotlin

StateFlow
在概念上与 Compose
State
类似,因为它表示可以观察到变化的单个值。在您的可组合项中,您可以像这样检索 uiState:

val uiState: MyUiState by viewModel.uiState.collectAsStateWithLifecycle()

为此,您需要将依赖项

androidx.lifecycle:lifecycle-runtime-compose
添加到您的 gradle 文件中。请参阅 https://medium.com/androiddevelopers/consuming-flows-safely-in-jetpack-compose-cde014d0d5a3 了解更多信息。

transformedFlow
将是您的存储库的组合流:

private fun transformedFlow(movieId: Int) = combine(
    myRepo.getMovie(movieId).filterNotNull(),
    myRepo.getActors(movieId)
) { movie, actors ->
    MyUiState(
        movie = movie,
        actorList = actors
    )
}
© www.soinside.com 2019 - 2024. All rights reserved.