【问题标题】:Different viewmodel for different composable functions inside same activity同一活动中不同可组合功能的不同视图模型
【发布时间】:2021-08-07 10:53:46
【问题描述】:

我在堆栈溢出的某处读到-

如果您正在创建一个新应用,您可以完全跳过使用 Fragments 并且只需使用可组合的函数来表示您的屏幕。

但是在使用片段时,我们可以为不同的片段/屏幕设置不同的视图模型。我们可以使用可组合功能实现相同的功能吗?例如单个活动、不同屏幕的不同可组合功能以及不同可组合功能的不同视图模型?如果是,是这种理想的方法?

【问题讨论】:

    标签: android android-fragments android-jetpack android-jetpack-compose


    【解决方案1】:

    但是在使用片段时,我们可以为不同的片段/屏幕使用不同的视图模型。

    在 Compose 中,您可以使用可组合的函数来显示屏幕 - 不再需要使用片段。

    我们可以用可组合功能实现相同的功能吗?比如单个活动、针对不同屏幕的不同组合功能以及针对不同可组合功能的不同视图模型?

    如果需要,您可以将不同的 ViewModel 用于不同的可组合功能。你可以这样做:

    class MainActivity : ComponentActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            setContent {
                DifferentViewModels()
            }
        }
    }
    
    @Composable
    fun DifferentViewModels() {
        Column {
            FirstComposable()
            SecondComposable()
        }
    }
    
    @Composable
    fun FirstComposable(firstViewModel: FirstViewModel = viewModel()) {
        Text(firstViewModel.value)
    }
    
    @Composable
    fun SecondComposable(secondViewModel: SecondViewModel = viewModel()) {
        Text(secondViewModel.value)
    }
    
    class FirstViewModel() : ViewModel() {
        val value = "Value from the first View Model"
    }
    
    class SecondViewModel() : ViewModel() {
        val value = "Value from the second View Model"
    }
    

    确保在 build.gradle(Module) 文件中添加 ViewModel 依赖项:

    // Compose ViewModel
    implementation "androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha07"
    

    如果是,这是理想的方法吗?

    这取决于您的项目要求。如果您有不同的大屏幕需要存储许多不同的值,并且不需要与不同的屏幕共享它们,则可以为它们使用不同的 ViewModel。

    如果屏幕很小和/或您需要在它们之间共享值,则共享一个 ViewModel 将是一种方式。

    【讨论】:

    • 这对我来说实际上是错误的:当导航出拥有视图模型的可组合时,视图模型没有被正确清除(即我似乎没有调用 onLCeared() 方法)。如果我对片段做同样的事情,那么视图模型生命周期就会得到正确维护......
    • "只要作用域还活着,ViewModel就会被保留。例如,如果在一个activity中使用了composable,viewModel()会返回同一个实例,直到activity结束或者进程被杀死。” Documentation
    • 而且屏幕旋转时似乎还会创建新的视图模型!这真是太糟了!这是否也发生在你们所有人身上,还是我做错了什么?我忘了补充:我也在使用撰写导航,可能是根本原因(否则,我的用法与此答案相同)...
    • 实际上,如果您完全按原样使用此答案的代码,则它是正确的。但是当您将它与组合导航一起使用时仍然很危险:在第一次导航操作到不同的可组合之后,上下文会以某种方式丢失并且每当屏幕旋转时都会重新创建视图模型(在第一个可组合导航之前,它按预期工作 - 即没有娱乐)。
    • 此外,撰写导航不会在屏幕外的视图模型上正确调用 onCleared()。根据我经历的不当行为,我会说谷歌正在努力实现这一目标(将视图模型生命周期正确绑定到撰写导航),但仍然没有。我们可能不得不等待谷歌让它更加成熟......
    【解决方案2】:

    你能做到吗?是的。你应该这样做吗?取决于您的用例,但根本不是问题。

    您可以选择这样做,但在这种情况下,最好的选择是让您的代码保持干净(可读和可维护)。因此,如果您正在为整个屏幕创建可组合的内容,我认为为每个屏幕使用多个视图模型是可行的,因为否则大量数据将被填充到一个单独的视图模型中。但是,您应该注意视图模型的维护。如果您在可组合项中初始化 vm,则它有可能被破坏(特别是如果您使用导航)。您必须在活动本身中将其声明为顶级。单个活动中的多个视图模型在视图世界中可能并不常见,但这样做没有问题。所以我的建议是选择适合您的特定用例的东西。如果您只想问是否可以这样做以及这样做是否有任何问题,那么您的答案是 - 是的和否(分别)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-29
      • 1970-01-01
      相关资源
      最近更新 更多