I have an question. How do I use global ViewModel instance which can be injected by Dagger/Hilt into any composables as shared instance?
I have MainNavigationViewModel which is handling some measurements tied to navigation bars and I want to share those measurements in some screens within NavHost.
So I'm initializing this ViewModel in my Activity like this:
@AndroidEntryPoint
class MainActivity : BaseActivity() {
override val viewModel : MainNavigationViewModel by viewModels()
override val screen: @Composable () -> Unit = {
MainNavigation(viewModel = viewModel)
}
}
And in individual composables I just use
@Composable
fun ScreenA(
navigationViewModel: MainNavigationViewModel = hiltViewModel(),
)
and then collecting MutableState
using viewmodel.state.collectAsStateWithLifecycle()
But for some reason it is returning wrong values (default ones from mutable state). Seems like every time I inject this ViewModel
it is different instance of it. I need shared instance.
So if MainNavigation will update some MutableState value inside this ViewModel, all screens where this ViewModel is defined will recompose if needed.
To scope the injected ViewModel
to the activity, provide the activity as viewModelStoreOwner
, for example:
fun Context.findActivity(): ComponentActivity? = when (this) {
is ComponentActivity -> this
is ContextWrapper -> baseContext.findActivity()
else -> null
}
@Composable
fun ScreenA(
navigationViewModel: MainNavigationViewModel = hiltViewModel(LocalContext.current.findActivity()!!),
)
//Or
@Composable
fun ScreenA(
navigationViewModel: MainNavigationViewModel = hiltViewModel(
checkNotNull(LocalContext.current.findActivity()) { "No ViewModelStoreOwner found" }
),
)
There is no need to create that ViewModel
in MainActivity
.