In my application, there are two nested navigations:
Every time a user navigates from SignedOut to SignedIn, a new instance of SharedViewModel must be provided.
The same instance of SharedViewModel must be shared between composables inside SignedIn.
The whole point of making SharedViewModel is that the app will be able to cache a massive amount of data between multiple composables avoiding fetching the same data several times.
ViewModel:
@HiltViewModel
class SharedViewModel @Inject constructor(): ViewModel() {
private val instance =
this.toString().substringAfterLast("@")
val data = instance
}
Module responsible for providing SharedViewModel:
@Module
@InstallIn(ViewModelComponent::class)
class SharedViewModelModule {
@Provides
@ViewModelScoped
fun provideSharedViewModel(): SharedViewModel =
SharedViewModel()
}
MainActivity.kt
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
val navigationController = rememberNavController()
NavHost(
navController = navigationController,
startDestination = "WelcomeScreen"
) {
navigation(route = "SignedOut", startDestination = "WelcomeScreen") {...}
navigation(route = "SignedIn", startDestination = "HomeScreen") {
composable(
route = "HomeScreen",
content = {
val viewModel = hiltViewModel<SharedViewModel>(it)
}
)
composable(
route = "SecondScreen",
content = {
val viewModel =hiltViewModel<SharedViewModel>(it)
}
)
}
}
}
}
}
I navigate from SignedOut to SignedIn: The same instance of SharedViewModel should be provided to both HomeScreen and SecondScreen composables.
I navigate from SignedIn to SignedOut and back to SignedIn: A completely new instance should be provided for HomeScreen and SecondScreen.
Dagger-hilt provides two different instances for HomeScreen and SecondScreen.
Please have a look at the Android ViewModel Cheatsheet:
As you can see denoted in the orange box, a ViewModel in Hilt by default is scoped to the closest ViewModelStoreOwner
, which in your case is a BackStackEntry
in your NavGraph
. However, you can obtain a ViewModel by its BackStackEntry
and use it in other destinations.
Please try the following code:
composable(
route = "HomeScreen",
content = {
val viewModel = hiltViewModel<SharedViewModel>(it)
}
)
composable(
route = "SecondScreen",
content = {
val homeEntry = remember(backStackEntry) {
navController.getBackStackEntry("HomeScreen")
}
val sharedViewModel = hiltViewModel<ParentViewModel>(homeEntry)
}
)