Skip to content
Related Articles
Open in App
Not now

Related Articles

Shared ViewModel in Android

Improve Article
Save Article
  • Difficulty Level : Easy
  • Last Updated : 14 Feb, 2022
Improve Article
Save Article

In android, we can use ViewModel to share data between various fragments or activities by sharing the same ViewModel among all the fragments and they can access everything defined in the ViewModel. This is one way to have communication between fragments or activities. Almost every application has some communication between various activities or fragments. 

What we are going to build in this article?

In the article, we are going to learn about Shared ViewModel in Android to communicate with other fragments. We will develop an application containing two fragments in which one fragment updates the data within the ViewModel which is shared between both the fragments and another fragment observes the changes on that data and displays the updated one on the screen. Application’s work is to send->receive->display a message. A sample GIF is given below to get an idea about what we are going to do in this article.

Step by Step Implementation

Step 1: Create a New Project

To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Note that select Kotlin as the programming language.

Step 2: Create a class SharedViewModel

Go to the SharedViewModel.kt file and refer to the following code. Below is the code for the SharedViewModel.kt file. Comments are added inside the code to understand the code in more detail.

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: Create two fragments and they are – MessageSenderFragment & MessageReceiverFragment

 

MessageSenderFragment – To send the message which will be received by MessageReceiverFragment. It will have a Button to send the message after clicking it. Go to the MessageSenderFragment.kt file and refer to the following code. Below is the code for the MessageSenderFragment.kt file. Comments are added inside the code to understand the code in more detail.

 

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)
        // observing the change in the message declared in SharedViewModel
        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 have created the object of SharedViewModel which is the same object as we are using the same single activity as an owner. This is the reason it is shared. Notice that we have used the requireActivity() in both the 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

 


My Personal Notes arrow_drop_up
Related Articles

Start Your Coding Journey Now!