简体   繁体   English

在 Jetpack Compose -> Composable 函数中使用输入参数启动 ViewModel

[英]Initiating a ViewModel with Input parameters in Jetpack Compose -> Composable function

I have a ViewModel that takes a string as an argument我有一个以字符串作为参数的 ViewModel

class ComplimentIdeasViewModel(ideaCategory : String) : ViewModel()  {
    //some code here
}

What is the best way to initiate this ViewModel inside a composable fun without using a ViewModel factory and Hilt?在不使用 ViewModel 工厂和 Hilt 的情况下,在可组合的乐趣中启动此 ViewModel 的最佳方法是什么? A simple statement seems to achieve this inside a composable fun一个简单的语句似乎在可组合的乐趣中实现了这一点

@Composable
fun SampleComposableFun() {
    val compIdeasViewModel = remember { ComplimentIdeasViewModel("someCategory") }
}

There is no warning in Android studio when I try to do this, but this seems too easy to be true, I am able to do this without Dependency Injection and with a ViewModelFactory class.当我尝试这样做时,Android studio 中没有警告,但这似乎太容易了,我可以在没有依赖注入和 ViewModelFactory 类的情况下做到这一点。 Am I missing something here?我在这里错过了什么吗?

This will not provide you the correct instance if viewmodel.如果 viewmodel,这不会为您提供正确的实例。 See if you store some state in the viewmodel, then using the factory to initialise it is necessary to ensure that you get the same and latest copy of the viewmodel currently present.看看你是否在 viewmodel 中存储了一些状态,然后使用工厂来初始化它是必要的,以确保你获得当前存在的 viewmodel 的相同和最新副本。 There is no error since the syntactic implementation is correct.没有错误,因为语法实现是正确的。 I do not know of any way to do this because most of the times, you don't need to.我不知道有什么方法可以做到这一点,因为大多数时候,您不需要这样做。 Why don't you initialise it in the top-level container, like the activity?为什么不在顶级容器中初始化它,比如活动? Then pass it down wherever necessary.然后在必要的地方传递它。

I've tried how you have written yours out and I had issues with screen rotation resetting the view model.我已经尝试过你是如何写出你的,但我在屏幕旋转重置视图模型时遇到了问题。 I suspect you may too.我怀疑你也可能。

I was able to fix it by utilizing the the factory parameter on viewModel() for this, which worked well for me.为此,我能够通过使用 viewModel() 上的工厂参数来修复它,这对我来说效果很好。 See this answer on a similar question with example on how to use it: jetpack compose pass parameter to viewModel请参阅有关如何使用它的示例的类似问题的此答案: jetpack compose pass parameter to viewModel

Create a CompositionLocal for your ViewModel .为您的ViewModel创建一个CompositionLocal

val YourViewModel = compositionLocalOf { YourViewModel(...) }

Then initialise it (You'd likely use the ViewModelProvider.Factory here).然后初始化它(您可能会在这里使用ViewModelProvider.Factory )。 And then provide that to your app.然后将其提供给您的应用程序。

CompositionLocalProvider(
  YourViewModel provides yourInitialisedViewModel,
) {
  YourApp()
}

Then reference it in the composable.然后在可组合中引用它。

@Composable
fun SampleComposableFun(
  compIdeasViewModel = YourViewModel.current
) {
  ... 
}

Note, the docs say that ViewModel s are not a good fit for CompositionLocal s because they will make your composable harder to test, make your composables tied to this app and make it harder to use @Preview .请注意,文档说ViewModel不适合CompositionLocal因为它们会使您的可组合更难测试,使您的可组合与此应用程序绑定并使其更难使用@Preview

Some get pretty angry about this.有些人对此非常生气。 However, if you manage to mock out the ViewModel , so you can test the app and use @Preview and your composables are tied to the app and not generic, then I see no problem.但是,如果您设法模拟ViewModel ,因此您可以测试应用程序并使用@Preview并且您的可组合物与应用程序相关联而不是通用的,那么我认为没有问题。

You can mock a ViewModel fairly simply, providing its dependencies are included as parameters (which is good practice anyway).您可以相当简单地模拟ViewModel ,只要它的依赖项作为参数包含在内(无论如何这是一个好习惯)。

open class MockedViewModel : MyViewModel(
  app = Application(),
  someOtherDependeny = MockedDependecy(),
)

The more dependencies your ViewModel has the more mocking you'll need to do.您的ViewModel依赖项越多,您需要做的模拟就越多。 But I've not found it prohibitive and including the ViewModel as a default parameter has massively sped up development.但是我没有发现它令人望而却步,并且将ViewModel作为默认参数包含在ViewModel加快了开发速度。

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

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