How to use NavController in compose ViewModel via hilt

Viewed 1797

I am using jetpack compose with the navigation compose library to navigate from one screen to the next. Usually you would have a ViewModel that would take care of user interactions (e.g.: viewModel.addItem()). In order to fulfill the addItem command i would like to show another screen via navController.navigate(). The ViewModel itself is injected into the Composable via hiltNavGraphViewModel().

Now the question is: How could i inject the NavController into the ViewModel via hilt?

@HiltViewModel
class ScreenViewModel @Inject constructor(
  private val navController: NavController // where does it come from?
) : ViewModel() {

  fun addItem() {
    navController.navigate("add-item-screen")
  }

}

The NavController is created via the rememberNavController() method up in the composable hirarchy. I also do not want to pass the controller down the composable hierarchy or use a CompositionLocal. The preferred approach would be to have the controller available in the ViewModel.

1 Answers

if you want to inject it to viewmodel, you should create navigation controller using application context, install it in application (singleton) component and mark it as singleton:

@Module
@InstallIn(SingletonComponent::class)
object NavigationModule {

    @Provides
    @Singleton
    fun provideNavController(@ApplicationContext context: Context) = NavHostController(context).apply {
        navigatorProvider.addNavigator(ComposeNavigator())
        navigatorProvider.addNavigator(DialogNavigator())
    }
}

but in my opinion this is not good practise

Related