According to the documentation from Android :
“Android architecture components are a collection of libraries that help you to build robust, testable, and maintainable apps.”
In Android architecture components there are many other components including classes used to manage the life cycle of UI components to handle data persistence.
“Managing your UI component lifecycle and handling data persistence”
In this article I will introduce you about ViewModel
and how to use it.
General introduction
ViewModel
is a class that is responsible for preparing and managing data for a UI component (be it Activity or Fragment). It also provides a way to easily communicate between activity and fragment or between fragments.
ViewModel
always created in the same scope (a fragment or an activity) and will be retained until the scope is “alive”. In other words, the ViewModel
will not be destroyed when its activity or fragment is destroyed by a configuration change (such as rotating the screen). These owners’ new instances will only reconnect to its existing ViewModel
.
ViewModel
life cycle (Reference: https://developer.android.com/topic/libraries/architecture/viewmodel )
The main purpose of the ViewModel
is to get and keep the information needed for activity and fragment. In addition, activity and fragment can observe changes in ViewModel
through the use of LiveData
or DataBinding
.
ViewModel
only responsible for managing the data for the UI so it never accesses the view hierarchy or keeps references to activity or fragment.
We will start with learning about the benefits of using ViewModel
Benefit
ViewModel
exists when screen recording or other configuration changes.ViewModel
still running while the activity is in the back stack.ViewModel
is lifecycle-aware.ViewModel
with the support ofLiveData
can respond to UI changes. Each time the data changes, the UI will be updated based on theLiveData
observation with the current data in theViewModel
.ViewModel
easy to understand and easy to test.
In this article, I will introduce to you three important aspects of ViewModel
.
- Create and use basic
ViewModel
. - Create and use
ViewModel
with parameters usingViewmodelProvide.Factory
. - Shared ViewModel for communication between activity and fragment.
Simple ViewModel
There are 4 main steps to creating and using ViewModel
:
- Add dependencies to app-level
build.gradle
. - Separate data with activity by creating a class that inherits
ViewModel
. - Create the
ViewModel
instance in the activity. - Establish communication between
ViewModel
andView
.
Add the dependencies
To use ViewModel
we have to add dependencies to app/build.gradle
1 2 3 | implementation <span class="token string">"android.arch.lifecycle:extensions:1.0.0"</span> annotationProcessor <span class="token string">"android.arch.lifecycle:compiler:1.0.0"</span> |
Or if you are using Kotlin vs AndroidX then add:
1 2 | implementation <span class="token string">'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'</span> |
Create ViewModel
class
To create a SampleViewModel
for Activity without any data, we just need to inherit from ViewModel
.
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">package</span> com <span class="token punctuation">.</span> example <span class="token punctuation">.</span> viewmodel <span class="token keyword">import</span> androidx <span class="token punctuation">.</span> lifecycle <span class="token punctuation">.</span> ViewModel <span class="token keyword">class</span> SampleViewModel <span class="token operator">:</span> <span class="token function">ViewModel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">onCleared</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span> <span class="token punctuation">.</span> <span class="token function">onCleared</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token comment">// Dispose All your Subscriptions to avoid memory leaks</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
onCleared()
: Will be called when the ViewModel
no longer in use and will be destroyed. It is useful when ViewModel
observe some data, and you need to clear them to avoid ViewModel
leak.
Create the ViewModel
instance in the activity
To create ViewModel
in actitvity we will use ViewModelProvider
. We need to pass the Context
and class name of ViewModel
to the ViewModelProvider
to get its instance.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <span class="token keyword">package</span> com <span class="token punctuation">.</span> example <span class="token punctuation">.</span> viewmodel <span class="token keyword">import</span> androidx <span class="token punctuation">.</span> appcompat <span class="token punctuation">.</span> app <span class="token punctuation">.</span> AppCompatActivity <span class="token keyword">import</span> android <span class="token punctuation">.</span> os <span class="token punctuation">.</span> Bundle <span class="token keyword">import</span> androidx <span class="token punctuation">.</span> lifecycle <span class="token punctuation">.</span> ViewModelProvider <span class="token keyword">class</span> MainActivity <span class="token operator">:</span> <span class="token function">AppCompatActivity</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">lateinit</span> <span class="token keyword">var</span> viewModel <span class="token operator">:</span> SampleViewModel <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">onCreate</span> <span class="token punctuation">(</span> savedInstanceState <span class="token operator">:</span> Bundle <span class="token operator">?</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span> <span class="token punctuation">.</span> <span class="token function">onCreate</span> <span class="token punctuation">(</span> savedInstanceState <span class="token punctuation">)</span> <span class="token function">setContentView</span> <span class="token punctuation">(</span> R <span class="token punctuation">.</span> layout <span class="token punctuation">.</span> activity_main <span class="token punctuation">)</span> viewModel <span class="token operator">=</span> <span class="token function">ViewModelProvider</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> SampleViewModel <span class="token operator">::</span> <span class="token keyword">class</span> <span class="token punctuation">.</span> java <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
ViewModelProvider
is a utility to get instance of ViewModel
in ViewModelStore
. It will return an instance of ViewModel
if it exists otherwise it will create a new one. ViewModelStore
will store ViewModel
by using HashMap
.
Establish communication between ViewModel
and View
Now we will start with how to get values from ViewModel
and put them into View
. First, we will create a LiveData
in the ViewModel
, and when we click on the button we will update its value and show toast message.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <span class="token keyword">package</span> com <span class="token punctuation">.</span> example <span class="token punctuation">.</span> viewmodel <span class="token keyword">import</span> androidx <span class="token punctuation">.</span> lifecycle <span class="token punctuation">.</span> LiveData <span class="token keyword">import</span> androidx <span class="token punctuation">.</span> lifecycle <span class="token punctuation">.</span> MutableLiveData <span class="token keyword">import</span> androidx <span class="token punctuation">.</span> lifecycle <span class="token punctuation">.</span> ViewModel <span class="token keyword">class</span> SampleViewModel <span class="token operator">:</span> <span class="token function">ViewModel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">val</span> _badgeCount <span class="token operator">=</span> MutableLiveData <span class="token operator"><</span> Int <span class="token operator">></span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">var</span> number <span class="token operator">=</span> <span class="token number">0</span> <span class="token keyword">val</span> badgeCount <span class="token operator">:</span> LiveData <span class="token operator"><</span> Int <span class="token operator">></span> <span class="token keyword">get</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=</span> _badgeCount <span class="token keyword">fun</span> <span class="token function">incrementBadgeCount</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> _badgeCount <span class="token punctuation">.</span> <span class="token function">postValue</span> <span class="token punctuation">(</span> <span class="token operator">++</span> number <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">onCleared</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span> <span class="token punctuation">.</span> <span class="token function">onCleared</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token comment">// Dispose All your Subscriptions to avoid memory leaks</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Now we will start UI code in Activity.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | <span class="token keyword">package</span> com <span class="token punctuation">.</span> example <span class="token punctuation">.</span> viewmodel <span class="token keyword">import</span> android <span class="token punctuation">.</span> os <span class="token punctuation">.</span> Bundle <span class="token keyword">import</span> android <span class="token punctuation">.</span> widget <span class="token punctuation">.</span> Toast <span class="token keyword">import</span> androidx <span class="token punctuation">.</span> appcompat <span class="token punctuation">.</span> app <span class="token punctuation">.</span> AppCompatActivity <span class="token keyword">import</span> androidx <span class="token punctuation">.</span> lifecycle <span class="token punctuation">.</span> Observer <span class="token keyword">import</span> androidx <span class="token punctuation">.</span> lifecycle <span class="token punctuation">.</span> ViewModelProvider <span class="token keyword">import</span> kotlinx <span class="token punctuation">.</span> android <span class="token punctuation">.</span> synthetic <span class="token punctuation">.</span> main <span class="token punctuation">.</span> activity_main <span class="token punctuation">.</span> <span class="token operator">*</span> <span class="token keyword">class</span> MainActivity <span class="token operator">:</span> <span class="token function">AppCompatActivity</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">lateinit</span> <span class="token keyword">var</span> viewModel <span class="token operator">:</span> SampleViewModel <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">onCreate</span> <span class="token punctuation">(</span> savedInstanceState <span class="token operator">:</span> Bundle <span class="token operator">?</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span> <span class="token punctuation">.</span> <span class="token function">onCreate</span> <span class="token punctuation">(</span> savedInstanceState <span class="token punctuation">)</span> <span class="token function">setContentView</span> <span class="token punctuation">(</span> R <span class="token punctuation">.</span> layout <span class="token punctuation">.</span> activity_main <span class="token punctuation">)</span> viewModel <span class="token operator">=</span> <span class="token function">ViewModelProvider</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> SampleViewModel <span class="token operator">::</span> <span class="token keyword">class</span> <span class="token punctuation">.</span> java <span class="token punctuation">)</span> <span class="token function">observeViewModel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token function">initListeners</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">private</span> <span class="token keyword">fun</span> <span class="token function">initListeners</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> btn_badge <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">setOnClickListener</span> <span class="token punctuation">{</span> viewModel <span class="token punctuation">.</span> <span class="token function">incrementBadgeCount</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">private</span> <span class="token keyword">fun</span> <span class="token function">observeViewModel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> viewModel <span class="token punctuation">.</span> badgeCount <span class="token punctuation">.</span> <span class="token function">observe</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token punctuation">,</span> Observer <span class="token punctuation">{</span> <span class="token function">showToast</span> <span class="token punctuation">(</span> it <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">private</span> <span class="token keyword">fun</span> <span class="token function">showToast</span> <span class="token punctuation">(</span> value <span class="token operator">:</span> Int <span class="token punctuation">)</span> <span class="token punctuation">{</span> Toast <span class="token punctuation">.</span> <span class="token function">makeText</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token punctuation">,</span> value <span class="token punctuation">.</span> <span class="token function">toString</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> Toast <span class="token punctuation">.</span> LENGTH_LONG <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">show</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Every time the data changes on badgeCount
via LiveData
, we will receive a callback via the registered Observer
, so our UI is always updated and gets the latest value.
We have finished creating the ViewModel
and communicating it with the activity. The following we will continue with ViewModelProvider.Factory
.
ViewModelProvider.Factory
As above, our ViewModel
does not accept any parameters, it is easy to do. However, what if we need to pass a parameter to the ViewModel
?
1 2 3 4 5 6 7 8 | <span class="token keyword">class</span> <span class="token function">SampleViewModel</span> <span class="token punctuation">(</span> name <span class="token operator">:</span> String <span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token function">ViewModel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">onCleared</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span> <span class="token punctuation">.</span> <span class="token function">onCleared</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token comment">// Dispose All your Subscriptions to avoid memory leaks</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
If we do the above, the result will be compile-time error.
1 2 | java <span class="token punctuation">.</span> lang <span class="token punctuation">.</span> RuntimeException <span class="token operator">:</span> Cannot create an instance of <span class="token keyword">class</span> <span class="token class-name">com <span class="token punctuation">.</span> example <span class="token punctuation">.</span> viewmodel <span class="token punctuation">.</span> SampleViewModel <span class="token punctuation">.</span></span> |
so we will need the ViewModelFactory
to do this.
ViewModelProvider()
creates a default ViewModelProvider.Factory
, with this ViewModelProvider.Factory
we will not be able to create ViewModel
with parameters. So when we add parameters to the ViewModel
constructor, the implementation of ViewModelProvider.Factory
will fail because it will call the primary constructor for creating the instance of ViewModel
.
ViewModelProvider.Factory
is the implementation of the factory interface, responsible for initializing ViewModel
. We need to re-implement the factory to be able to create a ViewModel
with parameters.
To do this, we will inherit from ViewModelProvider.Factory
and override the create()
which will create an instance of ViewModel
.
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">package</span> com <span class="token punctuation">.</span> example <span class="token punctuation">.</span> viewmodel <span class="token keyword">import</span> androidx <span class="token punctuation">.</span> lifecycle <span class="token punctuation">.</span> ViewModel <span class="token keyword">import</span> androidx <span class="token punctuation">.</span> lifecycle <span class="token punctuation">.</span> ViewModelProvider <span class="token keyword">class</span> <span class="token function">SampleViewModelFactory</span> <span class="token punctuation">(</span> <span class="token keyword">val</span> arg <span class="token operator">:</span> String <span class="token punctuation">)</span> <span class="token operator">:</span> ViewModelProvider <span class="token punctuation">.</span> <span class="token function">Factory</span> <span class="token punctuation">{</span> <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token operator"><</span> T <span class="token operator">:</span> ViewModel <span class="token operator">?</span> <span class="token operator">></span> <span class="token function">create</span> <span class="token punctuation">(</span> modelClass <span class="token operator">:</span> Class <span class="token operator"><</span> T <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token operator">:</span> T <span class="token punctuation">{</span> <span class="token keyword">return</span> modelClass <span class="token punctuation">.</span> <span class="token function">getConstructor</span> <span class="token punctuation">(</span> String <span class="token operator">::</span> <span class="token keyword">class</span> <span class="token punctuation">.</span> java <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">newInstance</span> <span class="token punctuation">(</span> arg <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
modelClass.getConstructor(String::class.java)
will get a constructor of type String
and create an instance of ViewModel
by calling newInstance()
and passing constructor value into this method.
Now we will do it in the activity
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">class</span> MainActivity <span class="token operator">:</span> <span class="token function">AppCompatActivity</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">lateinit</span> <span class="token keyword">var</span> viewModel <span class="token operator">:</span> SampleViewModel <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">onCreate</span> <span class="token punctuation">(</span> savedInstanceState <span class="token operator">:</span> Bundle <span class="token operator">?</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span> <span class="token punctuation">.</span> <span class="token function">onCreate</span> <span class="token punctuation">(</span> savedInstanceState <span class="token punctuation">)</span> <span class="token function">setContentView</span> <span class="token punctuation">(</span> R <span class="token punctuation">.</span> layout <span class="token punctuation">.</span> activity_main <span class="token punctuation">)</span> <span class="token keyword">val</span> factory <span class="token operator">=</span> <span class="token function">SampleViewModelFactory</span> <span class="token punctuation">(</span> <span class="token string">"sample"</span> <span class="token punctuation">)</span> viewModel <span class="token operator">=</span> <span class="token function">ViewModelProvider</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token punctuation">,</span> factory <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> SampleViewModel <span class="token operator">::</span> <span class="token keyword">class</span> <span class="token punctuation">.</span> java <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
If your ViewModel
has a dependency or a parameter and you want to create an instance of it, you need to create a custom ViewModelProvider.Factory
to pass that dependency or parameter.
1 2 3 | <span class="token keyword">val</span> factory <span class="token operator">=</span> <span class="token function">SampleViewModelFactory</span> <span class="token punctuation">(</span> <span class="token string">"sample"</span> <span class="token punctuation">)</span> <span class="token function">ViewModelProvider</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token punctuation">,</span> factory <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> SampleViewModel <span class="token operator">::</span> <span class="token keyword">class</span> <span class="token punctuation">.</span> java <span class="token punctuation">)</span> |
If you simply need to use it via ViewModelProvider(this)
to create an instance of ViewModel
.
1 2 | <span class="token function">ViewModelProvider</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> SampleViewModel <span class="token operator">::</span> <span class="token keyword">class</span> <span class="token punctuation">.</span> java <span class="token punctuation">)</span> |
Shared ViewModel for communication between activity and fragment
To communicate between different fragments, or between fragments and activities, we often use interfaces or target fragments. But it’s easier when we share a ViewModel
within the activity scope.
To complete the above flow, we need to create the ViewModel
instance used in the activity scope in the fragment, the activity will have only one instance created and shared with different fragments.
Problem
Communication between two or more fragments in the same activity is very common.
Assuming we have 2 fragments: Fragment1
allows the user to select an item from the list, Fragment2
will display the content of the selected item. In this case both fragments will define several interfaces to activity bind them together. In addition, both fragments must handle the task when either fragment has not been created or visible.
Solution
To solve the above problem we will share a ViewModel
for these fragments within the activity scope.
Now we will create a SharedViewModel
class
1 2 3 4 5 6 7 | <span class="token keyword">class</span> SharedViewModel <span class="token operator">:</span> <span class="token function">ViewModel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">val</span> selected <span class="token operator">=</span> MutableLiveData <span class="token operator"><</span> String <span class="token operator">></span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">fun</span> <span class="token function">selectedItem</span> <span class="token punctuation">(</span> item <span class="token operator">:</span> String <span class="token punctuation">)</span> <span class="token punctuation">{</span> selected <span class="token punctuation">.</span> value <span class="token operator">=</span> item <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Assuming we have 2 fragments: Fragment1
and Fragment2
attached in the main activity, we need to post something from Fragment1
to Fragment2
via a clicked button.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token keyword">class</span> Fragment1 <span class="token operator">:</span> <span class="token function">Fragment</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">lateinit</span> <span class="token keyword">var</span> viewModel <span class="token operator">:</span> SharedViewModel <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">onCreate</span> <span class="token punctuation">(</span> savedInstanceState <span class="token operator">:</span> Bundle <span class="token operator">?</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span> <span class="token punctuation">.</span> <span class="token function">onCreate</span> <span class="token punctuation">(</span> savedInstanceState <span class="token punctuation">)</span> viewModel <span class="token operator">=</span> activity <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">let</span> <span class="token punctuation">{</span> ViewModelProviders <span class="token punctuation">.</span> <span class="token function">of</span> <span class="token punctuation">(</span> it <span class="token punctuation">)</span> <span class="token punctuation">[</span> SharedViewModel <span class="token operator">::</span> <span class="token keyword">class</span> <span class="token punctuation">.</span> java <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token operator">?:</span> <span class="token keyword">throw</span> <span class="token function">Exception</span> <span class="token punctuation">(</span> <span class="token string">"Activity is null"</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> btn <span class="token punctuation">.</span> <span class="token function">setOnClickListener</span> <span class="token punctuation">{</span> viewModel <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">selectedItem</span> <span class="token punctuation">(</span> <span class="token string">"New Item posted"</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <span class="token keyword">class</span> Fragment2 <span class="token operator">:</span> <span class="token function">Fragment</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">lateinit</span> <span class="token keyword">var</span> viewModel <span class="token operator">:</span> SharedViewModel <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">onViewCreated</span> <span class="token punctuation">(</span> view <span class="token operator">:</span> View <span class="token punctuation">,</span> savedState <span class="token operator">:</span> Bundle <span class="token operator">?</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span> <span class="token punctuation">.</span> <span class="token function">onViewCreated</span> <span class="token punctuation">(</span> view <span class="token punctuation">,</span> savedInstanceState <span class="token punctuation">)</span> <span class="token comment">//ViewModel Creation using activity scope</span> activity <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">let</span> <span class="token punctuation">{</span> ViewModelProviders <span class="token punctuation">.</span> <span class="token function">of</span> <span class="token punctuation">(</span> it <span class="token punctuation">)</span> <span class="token punctuation">[</span> SharedViewModel <span class="token operator">::</span> <span class="token keyword">class</span> <span class="token punctuation">.</span> java <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token operator">?:</span> <span class="token keyword">throw</span> <span class="token function">Exception</span> <span class="token punctuation">(</span> <span class="token string">"Activity is null"</span> <span class="token punctuation">)</span> <span class="token comment">//Observe data changes from ViewModel and update the UI</span> model <span class="token punctuation">.</span> selected <span class="token punctuation">.</span> <span class="token function">observe</span> <span class="token punctuation">(</span> viewLifecycleOwner <span class="token punctuation">,</span> Observer <span class="token operator"><</span> Item <span class="token operator">></span> <span class="token punctuation">{</span> item <span class="token operator">-></span> Toast <span class="token punctuation">.</span> <span class="token function">makeText</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token punctuation">,</span> item <span class="token punctuation">,</span> Toast <span class="token punctuation">.</span> LENGTH_LONG <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">show</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
ViewModelProvider
will return these two fragments together with an instance of SharedViewModel
in the activity scope.
This approach offers the following benefits:
- Activity does not need to do anything about this communication.
- Fragments don’t need to know each other, they just need
SharedViewModel
. When one fragment is disappears, the other fragment will function normally. - Each fragment is active with its own life cycle, and is not affected by other fragments. So, if a fragment is replaced, the UI continues to work without any problems.
So, we are done communicating between UI components.