2

I have a ViewModel that I'm already injecting into a Composable. Now I want to inject the same instance of that ViewModel into my Activity. For example:

In AccountScreen.kt

@Composable
fun AccountScreen(accountViewModel: AccountViewModel = hiltViewModel()) {
    ...
}

and my Activity class:

class MainActivity : ComponentActivity() {
    @Inject
    lateinit var accountViewModel: AccountViewModel
}

should have the same instance of AccountViewModel.

I know using @Inject in the Activity as in the example above doesn't work. Hilt's documentation suggests using ViewModelProvider or by viewModels() instead, both of which give me a new instance of AccountViewModel, but I need the same instance as what's in the AccountScreen Composable.

AtomicStrongForce
  • 529
  • 1
  • 5
  • 11
  • Just to make it clear, since I'm reading it in the opposite direction, Account Screen was initialized with ViewModel(xyz instance), you simply want to have the MainActivity with same ViewModel(xyz instance) as well, is AccountScreen part of the content of MainActivity? – z.g.y Dec 13 '22 at 01:36
  • AccountScreen is a separate Composble in a separate file. However MainActivity is the only Activity in the app, so one could consider AccountScreen as running "under" MainActivity – AtomicStrongForce Dec 13 '22 at 02:20
  • you can check this [post](https://stackoverflow.com/questions/74593974/share-viewmodel-from-activity-to-compose-function-using-hilt/74598073#74598073) – z.g.y Dec 13 '22 at 02:51

2 Answers2

2

I'm assuming AccountScreen is part of a NavGraph, since you mentioned you need same instance of the view model, you can consider specifying the ViewModelStoreOwner when you inject your ViewModel in your AccountScreen, so MainActivity and AccountScreen will share same instance of it.

@Composable
fun MyNavHost(
    ...
) {

    val viewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) {
        "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner"
    }

    NavHost(
        modifier = modifier,
        navController = navController,
        startDestination = startDestination
    ) {

        composable(<Destination>) {  
           AccountScreen(accountViewModel: AccountViewModel = hiltViewModel(viewModelStoreOwner)) {
                  ...
           }
        }

        ...
    }
}
z.g.y
  • 5,512
  • 4
  • 10
  • 36
1

I ended up solving this by getting the parent Activity's ViewModel in my child Composable (AccountScreen in this case) like so:

val composeView = LocalView.current
val activityViewModel = composeView.findViewTreeViewModelStoreOwner()?.let {
    hiltViewModel<MyViewModel>(it)
}

Within my MainActivity I'm getting the ViewModel the standard way

private val accountViewModel: AccountViewModel by viewModels()

Thanks to @z.g.y for providing a helpful suggestion that led me to this solution.

AtomicStrongForce
  • 529
  • 1
  • 5
  • 11