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?
- 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.