10

I have viewModel for my ProfileScreen.

@Composable
fun ProfileScreen() {
    val viewModel: ProfileViewModel = viewModel()
    ...
}

Every time when I call ProfileScreen, new viewModel is created. How can I created only one viewModel instance for my ProfileScreen. I tried to inject viewModel following https://insert-koin.io/docs/reference/koin-android/compose/ but when I try

val viewModel: ProfileViewModel = viewModel()

Android Studio throws error.

Wafi_ck
  • 1,045
  • 17
  • 41

4 Answers4

3

Your viewModel gets destroyed whenever you destroy the composable, it can survive re-compositions but as soon as your composable gets destroyed it will be destroyed.

What you can do is create the viewModel in a scope that lives longer than the ProfileScreen composable and then pass the viewModel as parameter to it.

Something like this should work.

@Composable 
fun MainScreen() {
     val vModel : ProfileViewModel = viewModel()
     ....
     ProfileScreen(vModel)
}
Omar Walid
  • 51
  • 1
  • 5
3

Or use remember() for save instance ViewModel between recompose calls

@Composable
fun ProfileScreen() {
    val viewModel = remember { ProfileViewModel() }
    ...
}

Also, rememberSaveable allows saving state(aka data class) between recreating of activity

jershell
  • 115
  • 1
  • 4
  • When I try it I get error comes from remeber{}: remember calls must not return Unit, Type mismatch. Required: ProfileViewModel Found: Unit Should I define somewhere my ProfileViewModel() class? – Wafi_ck Jun 13 '21 at 19:18
  • 1
    By calling remember it will survive recomposition, but no't if device orientation will change. It will act like a normal class which is remember in current composition, not like a typical android viewModel. – ShadeToD Sep 22 '21 at 09:05
  • 1
    `remember` will also not survive if the ProfileScreen is in the back stack (when using Compose Navigation or Fragments) or with any other configuration change (like split-screen, dark mode switch, etc.), not just orientation change. – Sebas LG Dec 23 '21 at 20:33
  • This is a bad pattern – ShadeToD Jan 25 '22 at 20:17
3

If u want to use Koin to inject your view model to composable you should follow what is described in the docs.

getViewModel() - fetch instance

By calling that method Koin will search for that view model and will provide with an instance.

Here is an example of injecting view model in my app.

fun ManualControlScreen(
  onDrawerClick: () -> Unit,
  viewModel: ManualControlViewModel = getViewModel<ManualControlViewModel>()
) {
   // Your composable UI
}
ShadeToD
  • 403
  • 9
  • 22
0

Try this:

@Composable
fun HomeScreen(viewModel: PokemonViewModel = koinViewModel()) {
}

build.gradle(:app)

def koin_version = '3.3.2'
implementation "io.insert-koin:koin-core:$koin_version"
implementation "io.insert-koin:koin-android:$koin_version"
implementation 'io.insert-koin:koin-androidx-compose:3.4.1'

SOURCE

francis
  • 3,852
  • 1
  • 28
  • 30