Jetpack Compose Navigation with ViewModel

🚪Problem

I want to implement an architecture in my Jetpack Compose Application. Also, do navigations because I have several pages in my app.

🗝 Solution

Use ViewModel and Navigation separate. How?

  1. Import ViewModel & Navigation Libraries.

⚠️ Caution: be sure to import lifecycle-viewmodel-compose

2. Create a Navigation Composable function and pass your navHostController which, is accessed by rememberNavController()

3. Create your viewModel Classes separate as you did before and continue your development.

❌ Soon, you will notice that this approach won’t work in a more scaled application, and you need to implement a better architecture. ❌

So you may wonder how I can handle my navigations in My ViewModel classes and don’t pass both ViewModel and navController to each compose function.

If you are familiar with ViewModel previous, you would know that it is a singleton class that is created with the following snippet:

So to pass a variable to a ViewModel class, we need to create the ViewModelFactory class and pass it to the ViewModel like the following:

Last but not least we extract navigations as functions and pass them with ViewModel like so:

💡 Extra Point: How to pass down navigation functions with arguments?

The secret is passing lambdas instead of functions and passing the parameter in the desired location in your code

Ok, let’s implement this using Dependency Injection.

💉Using DI

I use Hilt for DI. The benefit of using DI is that there is no need for ViewModelFactory classes anymore. This helps us have a much cleaner code.

To implement, we use @HiltViewModel and inject the Navigator class in the constructor of our ViewModel class.

Our Navigator Class is the following object responsible to provide our navHostController (Notice: navHostController is wrapped in this class because we want to inject it in our ViewModel classes)

⚠️ Caution: there is a flaw here: the memory leak caused by the navController initialization method. I’ll be glad if you could provide a better architecture in the comments. Also, be aware of handling this leak manually.

Finally, there is no need to create a ViewModel instance in the Navigation class; you get your viewModel by passing hiltViewModel() as the param of your View.

Note that you should add the following dependency of Hilt in your app’s Gradle file:

Now you can concentrate on your creativity instead of thinking about the architecture.

The solution to memory leak and another approach that is better than mine can be found here:

https://proandroiddev.com/how-to-make-jetpack-compose-navigation-easier-and-testable-b4b19fd5f2e4

Don’t forget to clap and share if you enjoyed this article. Also, I am really looking forward to seeing your opinions in the comments.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store