简体   繁体   中英

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

I have a ViewModel that takes a string as an argument

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? 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. Am I missing something here?

This will not provide you the correct instance if 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. 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. See this answer on a similar question with example on how to use it: jetpack compose pass parameter to viewModel

Create a CompositionLocal for your ViewModel .

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

Then initialise it (You'd likely use the ViewModelProvider.Factory here). 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 .

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.

You can mock a ViewModel fairly simply, providing its dependencies are included as parameters (which is good practice anyway).

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

The more dependencies your ViewModel has the more mocking you'll need to do. But I've not found it prohibitive and including the ViewModel as a default parameter has massively sped up development.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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