Shared ViewModel in Android
In Android development, ViewModel serves as a means to facilitate data sharing among different fragments or activities. By utilizing the same ViewModel across multiple fragments, each fragment gains access to the shared data and functionality encapsulated within the ViewModel. This approach offers a streamlined method for enabling communication between various components within an application, a common requirement across most apps.Â
What we will build in this article?
In this article, we’ll deep dive into Shared ViewModel usage in Android for inter-fragment communication. Our focus will be on building an application featuring two fragments. One fragment will be responsible for updating data within a shared ViewModel, while the other fragment will observe these changes and display the updated content on the screen. The application’s core functionality revolves around sending, receiving, and displaying messages. A preview GIF is provided below to offer insight into the tasks we’ll accomplish throughout this article.
Step-by-Step Implementation
Step 1: Project Creation
Begin by creating a new project in Android Studio. For guidance on how to initiate a new project, please consult the “How to Create/Start a New Project in Android Studio” resource. Ensure that Kotlin is chosen as the programming language.
Step 2: SharedViewModel Class Creation
Navigate to the SharedViewModel.kt file and incorporate the provided code snippet below. This code outlines the structure of the SharedViewModel class. Detailed comments are included within the code to enhance comprehension.
Kotlin
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class SharedViewModel : ViewModel() {
val message = MutableLiveData<String>()
fun sendMessage(text: String) {
message.value = text
}
}
|
Â
Â
Step 3: Fragment Creation
Proceed to create two fragments: MessageSenderFragment and MessageReceiverFragment.
MessageSenderFragment: This fragment is responsible for sending messages to be received by the MessageReceiverFragment. It will feature a button that, upon clicking, will trigger the message sending process.
To implement this, navigate to the MessageSenderFragment.kt file and utilize the provided code snippet below. Detailed comments are included within the code to aid in understanding its functionality.
Kotlin
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import androidx.lifecycle.ViewModelProvider
class MessageSenderFragment : Fragment() {
lateinit var btn: Button
lateinit var writeMSg: EditText
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_message_sender, container, false )
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super .onViewCreated(view, savedInstanceState)
btn = view.findViewById(R.id.button)
writeMSg = view.findViewById(R.id.writeMessage)
val model = ViewModelProvider(requireActivity()).get(SharedViewModel:: class .java)
btn.setOnClickListener { model.sendMessage(writeMSg.text.toString()) }
}
}
|
Navigate to the app > res > fragment_message_sender.xml and add the below code to that file. Below is the code for the fragment_message_sender.xml file.
Â
XML
<? xml version = "1.0" encoding = "utf-8" ?>
< androidx.constraintlayout.widget.ConstraintLayout
android:layout_width = "match_parent"
android:layout_height = "match_parent" >
< EditText
android:id = "@+id/writeMessage"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:hint = "Write your message"
android:textAlignment = "center"
app:layout_constraintBottom_toTopOf = "@+id/button"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toTopOf = "parent" />
< Button
android:id = "@+id/button"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_marginBottom = "100dp"
android:text = "Share Your Message"
app:layout_constraintBottom_toBottomOf = "parent"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent" />
</ androidx.constraintlayout.widget.ConstraintLayout >
|
Â
Â
MessageReceiverFragment – To receive the message sent by MessageSenderFragment. It will have a TextView to show the updated message on the screen. Go to the MessageReceiverFragment.kt file and refer to the following code. Below is the code for the MessageReceiverFragment.kt file. Comments are added inside the code to understand the code in more detail.
Kotlin
class MessageReceiverFragment : Fragment() {
lateinit var displayMsg: TextView
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_message_receiver, container, false )
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super .onViewCreated(view, savedInstanceState)
displayMsg = view.findViewById(R.id.textViewReceiver)
val model = ViewModelProvider(requireActivity()).get(SharedViewModel:: class .java)
model.message.observe(viewLifecycleOwner, Observer {
displayMsg.text = it
})
}
}
|
Â
Â
Navigate to the app > res > fragment_message_receiver.xml and add the below code to that file. Below is the code for the fragment_message_receiver.xml file.
Â
XML
<? xml version = "1.0" encoding = "utf-8" ?>
< androidx.constraintlayout.widget.ConstraintLayout
android:layout_width = "match_parent"
android:layout_height = "match_parent" >
< TextView
android:id = "@+id/textViewReceiver"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:textSize = "20sp"
android:textColor = "@color/black"
android:textAlignment = "center"
app:layout_constraintBottom_toBottomOf = "parent"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toTopOf = "parent" />
</ androidx.constraintlayout.widget.ConstraintLayout >
|
Â
Â
We’ve instantiated the SharedViewModel object, which is shared among fragments due to the fact that they share the same activity as their owner. This is facilitated by utilizing the requireActivity() method within both fragments.
Â
. . .
ViewModelProvider(requireActivity()).get(SharedViewModel::class.java)
. . .
Â
Step 3: Update the activity_main.xml
Â
The activity consists of two fragments and is the host for both the fragments.
XML
<? xml version = "1.0" encoding = "utf-8" ?>
< androidx.constraintlayout.widget.ConstraintLayout
android:layout_width = "match_parent"
android:layout_height = "match_parent"
tools:context = ".MainActivity" >
< fragment
android:id = "@+id/receiverFragment"
android:name = "com.gfg.article.sharedviewmodel.MessageReceiverFragment"
android:layout_width = "match_parent"
android:layout_height = "0dp"
android:layout_marginStart = "8dp"
android:layout_marginTop = "8dp"
android:layout_marginEnd = "8dp"
android:layout_marginBottom = "8dp"
app:layout_constraintBottom_toTopOf = "@+id/senderFragment"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintHorizontal_bias = "0.5"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toTopOf = "parent" />
< fragment
android:id = "@+id/senderFragment"
android:name = "com.gfg.article.sharedviewmodel.MessageSenderFragment"
android:layout_width = "match_parent"
android:layout_height = "0dp"
android:layout_marginStart = "8dp"
android:layout_marginTop = "8dp"
android:layout_marginEnd = "8dp"
android:layout_marginBottom = "8dp"
app:layout_constraintBottom_toBottomOf = "parent"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintHorizontal_bias = "0.5"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toBottomOf = "@+id/receiverFragment" />
</ androidx.constraintlayout.widget.ConstraintLayout >
|
Â
Â
MainActivity.kt remains as it is.
Â
Kotlin
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super .onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
|
Â
Â
Now, Run the app.
Â
Output:
Â
Â
Source Code: Click Here
Â
Last Updated :
23 Feb, 2024
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...