简体   繁体   English

使用 SharedFlow 执行单次操作而不强制转换为所需的值

[英]Performing single shot operations using SharedFlow without casting to needed value

I have the following SharedFlow in my viewmodel -我的视图模型中有以下 SharedFlow -

class HeroesViewModel(private val heroesRepositoryImpl: HeroesRepositoryImpl) : ViewModel() {

    private val _uiState = MutableStateFlow(UiState())
    val uiState = _uiState.asStateFlow()

    private val _uiAction = MutableSharedFlow<UiAction>()
    val uiAction = _uiAction.asSharedFlow()

 sealed class UiAction {
        data class NavigateToHeroesDetails(val heroModel: HeroModel) : UiAction()
    }

And I implement the observing of it in my Composable screen -我在我的可组合屏幕中实现了对它的观察 -

fun DashboardScreen(
    navigator: DestinationsNavigator,
    viewModel: HeroesViewModel = get()
) {
    val uiState by viewModel.uiState.collectAsState()
    val uiAction by viewModel.uiAction.collectAsState(initial = null)

    when (uiAction) {
        is HeroesViewModel.UiAction.NavigateToHeroesDetails -> {
            navigator.navigate(HeroDetailsScreenDestination(uiAction.heroModel)) // Here is where I get the compiler error
        }
        null -> Unit
    }

When trying to use the information from the action, the compiler gives me the following error -尝试使用操作中的信息时,编译器给我以下错误 -

Smart cast to 'HeroesViewModel.UiAction.NavigateToHeroesDetails' is impossible, because 'uiAction' is a property that has open or custom getter

What would be the correct way verify that the variable is indeed of the type I want?验证变量确实是我想要的类型的正确方法是什么?

If you want to keep the by delegate then a simple way is to assign to a val inside the when expression如果您想保留by委托,那么一种简单的方法是在when表达式中分配一个val

    val uiAction by viewModel.uiAction.collectAsState(initial = null)
    
    @Suppress("UnnecessaryVariable")
    when (val action = uiAction) {
        is HeroesViewModel.UiAction.NavigateToHeroesDetails -> {
            HeroDetailsScreenDestination(action.heroModel)
        }
        null -> Unit
    }

There are other ways as well还有其他方法

  • with(uiAction) { when (this) {... } }
  • uiAction.run { when (this) {... } }
  • uiAction.let { when (it) {... } }

If you don't need the by delegate, then you can do如果您不需要代理by ,那么您可以这样做

    val uiAction = viewModel.uiAction.collectAsState(initial = null)

    when (val action = uiAction.value) {
        is HeroesViewModel.UiAction.NavigateToHeroesDetails -> {
            HeroDetailsScreenDestination(action.heroModel)
        }
        null -> Unit
    }

And if you just need read-only access in the current scope, then you can simplify it to如果您只需要当前 scope 中的只读访问权限,那么您可以将其简化为

    val uiAction = viewModel.uiAction.collectAsState(initial = null).value

    when (uiAction) {
        is HeroesViewModel.UiAction.NavigateToHeroesDetails -> {
            HeroDetailsScreenDestination(uiAction.heroModel)
        }
        null -> Unit
    }

So the answer that helped me to achieve my goal was to initiate a coroutine using the LaunchedEffect block, and inside it collecting the latest UI action -因此,帮助我实现目标的答案是使用LaunchedEffect块启动协程,并在其中收集最新的 UI 动作 -

LaunchedEffect(key1 = "") {
        viewModel.uiAction.collect { uiAction ->
            when (uiAction) {
                is HeroesViewModel.UiAction.NavigateToHeroesDetails -> {
                    navigator.navigate(HeroDetailsScreenDestination(uiAction.heroModel))
                }
            }
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM