Open In App
Related Articles

Shared ViewModel in Android

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Report issue
Report

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() {
   
    // variable to contain message whenever
    // it gets changed/modified(mutable)
    val message = MutableLiveData<String>()
   
    // function to send message
    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() {
   
      // to send message
    lateinit var btn: Button 
     
      // to write message
    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)
           
          // reference for button and EditText
        btn = view.findViewById(R.id.button)
        writeMSg = view.findViewById(R.id.writeMessage)
           
          // create object of SharedViewModel
        val model = ViewModelProvider(requireActivity()).get(SharedViewModel::class.java)
           
          // call function "sendMessage" defined in SharedVieModel
          // to store the value in message.
        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() {
    // to contain and display shared message
    lateinit var displayMsg: TextView
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // inflate the fragment layout
        return inflater.inflate(R.layout.fragment_message_receiver, container, false)
    }
  
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // reference for the container declared above
        displayMsg = view.findViewById(R.id.textViewReceiver)
        // create object of SharedViewModel
        val model = ViewModelProvider(requireActivity()).get(SharedViewModel::class.java)
  
        model.message.observe(viewLifecycleOwner, Observer {
            // updating data in displayMsg
            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
    xmlns:tools="http://schemas.android.com/tools"
    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
Previous
Next
Share your thoughts in the comments
Similar Reads