Using navigation component in ViewModels on Android(MVVM Architecture)
In this article, I will be talking about navigation. Nowadays in Android development, the best practice is to use single activity and multiple fragments. Using single activity and multiple fragments introduces a process that needs to be handled. That process is navigation between fragments.
When we use MVVM architecture in our development, we can manage navigation between fragments in ViewModels. Today I will be talking about how to handle navigations between fragments in ViewModels.
In this article I will be use Kotlin for development language. Also I will use Hilt for dependency injection.
We want to use an element in ViewModel that is stores data but only consumed once. In this way, we can use this element in the navigation process. We will use Event Wrapper for this goal. For more details about Event Wrapper please refer to the below link;
LiveData with SnackBar, Navigation and other events (the SingleLiveEvent case)
2021 Update: This guidance is deprecated in favor of the official guidelines.
First of all, you need some configurations and classes before the tutorial. You need to integrate the Hilt dependency injection library into your app. Then we will create some base classes and a sealed class to use for navigation.
Let’s create a sealed class called NavigationCommand. This class has two subclasses. One of them stores NavDirections value. This is the value we will use for navigation between fragments. The other one is just an object. We will use this value to navigate back.
Next, we will create a BaseViewModel class. We will extend this class in our ViewModels and use some values and functions in it for navigation.
As you can see above we have an instance called navigation. This instance is a MutableLiveData and stores wrapped NavigationCommand value. These values are wrapped with Event<T>.
Why are we using Event<T>. Because we want to use this value only once. Let’s say you show snack bar or toast messages using LiveData/MutableLiveData. When you rotate your screen the messages will be shown once again. Or you can use LiveData/MutableLiveData to show dialogs. When you rotate your screen dialog will be shown again. We don’t want this behavior. We want to store the value and we just want to use this value only once.
We created BaseViewModel, now we need BaseFragment class. To handle navigation operations in one place, we have to observe the navigation instance that we created in BaseViewModel. We will create BaseFragment as below;
So what are we doing here? This class is an abstract class, we are initializing common properties and functions that we will use in our fragments. We are performing the abstraction in OOP.
Additionally, as you can see above, there are observeNavigation and handleNavigation functions in exist in BaseFragment. The ViewModel classes that we will use in our fragments will extend BaseViewModel class. In this way, we would observe the navigation process and perform the operation. We are observing navigation value in observeNavigation function and in handleNavigation function, we are performing operations here using findNavController().
You might think that what observeNonNull function is. It is an extension function I use for observe MutableLiveData/LiveData instances. You can just use Observe() function that generally use.
Now everything is all set. Let’s see some usage. We will create two fragments then I will share the gif and Github repository.
First let’s create FirstSceneFragment;
As you can above there is FragmentFirstSceneBinding instance and FirstSceneViewModel that we need. Let’s create them too.
As you can see above, there are two functions we use to navigate in SecondSceneFragment. One is just navigation, not includes arguments. The other one is carrying some data while navigating. These are the two samples of this structure usage.
Now its time to create XML file;
We make root layout in our XML is <layout></layout>. It is a requirement for using DataBinding. As you can see in the XML file, we use the button click events here and trigger the functions from here. This is a DataBinding usage example.
Let’s say the user did some operations and after the operations are done you want to go back to the previous fragment. You can simply call navigateBack() function in ViewModel to do that operation like below;
In this article, we learned how to handle navigation operations from ViewModel in MVVM architecture. This Event wrapper usage can also use to show a dialog, snack bar, etc. I hope it was a useful article. You can find the related repository below. Thank you.