It’s very common in the Android application that two or more Fragments in an Activity need to communicate with each other. Let see a common case of master-detail fragments, where you have a fragment in which the user selects an item from a list and another fragment that displays the contents of the selected item. In this tutorial, we are using a ViewModel class as an interface between Fragments to sharing data.
What are Fragments :
Android Fragment represents a behavior or a portion of user interface in an Activity (or in FragmentActivity). You can use multiple fragments in a single activity to build a multi-pane UI and can reuse a fragment in multiple activities.
ViewModel :
The ViewModel class is designed to store and manage UI-related data in a lifecycle-conscious way. Here we are using the ViewModel class as an interface between Fragments to sharing data.
Consider we have 2 fragments Sender and Receiver and Suppose you need to share data between Sender and Receiver.
For this, you have to create a ViewModel class and implements methods in Sender pass the data to the Receiver, where receiver have an observer to see change and update UI accordingly.
Let’s start building basic: How to share data Between two fragments
Step 1. Create an android project in the android studio (Android First Program in Android Studio)
Step 2. Create 2 fragments in activity_main.xml
add following code :
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="in.eyehunt.commFragmentsViewModel.MainActivity"> <fragment android:id="@+id/frg_Receiver" android:name="in.eyehunt.commFragmentsViewModel.ReceiverFragment" android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginBottom="8dp" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" app:layout_constraintBottom_toTopOf="@+id/frg_Sender" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> </fragment> <fragment android:id="@+id/frg_Sender" android:name="in.eyehunt.commFragmentsViewModel.SenderFragment" android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginBottom="8dp" android:layout_marginEnd="8dp" android:layout_marginStart="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/frg_Receiver"> </fragment> </android.support.constraint.ConstraintLayout>
Step 3. Create new class SharedViewModel and extend View Model
Initialize variable “message” for sharing data and Generate Getter and setter.
package in.eyehunt.ShareFragmentsViewModel; import android.arch.lifecycle.MutableLiveData; import android.arch.lifecycle.ViewModel; public class SharedViewModel extends ViewModel { private final MutableLiveData message = new MutableLiveData(); public void setMessage(String msg){ message.setValue(msg); } public MutableLiveData getMessage() { return message; } }
Step 4. Create a layout and activity file for sender fragment with a button to send a message
Copy paste code must add color code in res/values/colors.xml before its throw error
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#000000</color> <color name="colorPrimaryDark">#000000</color> <color name="colorAccent">#ffffff</color> <color name="colorSen">#009688</color> <color name="colorRec">#3f51b5</color> <color name="White">#ffffff</color> </resources>
Then sender layout file
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorSen" tools:context="in.eyehunt.ShareFragmentsViewModel.SenderFragment"> <Button android:id="@+id/btn_sender" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:layout_gravity="center" android:gravity="center" android:text="Send Hello" /> </RelativeLayout>
Create an activity class for Sender
Note: when you are creating sender file that time also can generate layout file for the same fragment.
Create an instance of SharedViewModel model
and button.setOnClickListener
to send data
package in.eyehunt.ShareFragmentsViewModel; import android.arch.lifecycle.ViewModelProviders; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; public class SenderFragment extends Fragment { private SharedViewModel model; public SenderFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_sender, container, false); model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class); Button button = (Button) view.findViewById(R.id.btn_sender); // on click button button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { model.setMessage("Hello Fragment i am Sender - ViewModel"); } }); return view; } }
Step 6. Create a layout and activity file for the receiver
Add TextView in Fragments to show shared data
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorRec" tools:context="in.eyehunt.ShareFragmentsViewModel.ReceiverFragment"> <TextView android:id="@+id/tv_receiver" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true" android:gravity="center" android:text="Receiver" android:textColor="@color/White" android:textSize="18sp"/> </RelativeLayout>
Create an activity class for Receiver
get the result in ViewModel object observer and show in TextView.
package in.eyehunt.ShareFragmentsViewModel; import android.arch.lifecycle.Observer; import android.arch.lifecycle.ViewModelProviders; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class ReceiverFragment extends Fragment { TextView tv_msg; public ReceiverFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_receiver, container, false); final SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class); tv_msg = (TextView) view.findViewById(R.id.tv_receiver); model.getMessage().observe(this, new Observer() { @Override public void onChanged(@Nullable Object o) { tv_msg.setText(o.toString()); } }); return view; } }
Output Screenshot: Before
After click button “SEND HELLO”
Download Link and Source code Share data between fragments used ViewModel example
https://github.com/EyeHunts/ShareFragmentsViewModel
Code in Kotin
https://github.com/EyeHunts/ShareFragmentsViewModelK
Note : This example (Project) is developed in Android Studio 3.0.1 ,tested on Android 7.1.1 ( Android Nougat), compile SDK version API 26: Android 8.0 (Oreo)
MinSdkVersion=”15″
TargetSdkVersion=”26″
Coding in JAVA
Bonus: For share data between fragment using interface check this tutorial: Basic Communication between two fragments (Pass data)
Thank you,
easy and clear example
For view model viewmodelfactory is preferred to provide instance of viewmodel
Hello, can you help me achieve the same result in Kotlin?
Specifically on the part of the receiver, because I think I’ve got everything else already.
Check tutoiral, we updated kotlin source code…
class ReceiverFragment : Fragment() {
internal lateinit var tv_msg: TextView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_receiver, container, false)
val model = ViewModelProviders.of(activity!!).get(SharedViewModel::class.java)(R.id.tv_receiver) as TextView
tv_msg = view.findViewById
model.message.observe(this, object : Observer {
override fun onChanged(o: Any?) {
tv_msg.text = o!!.toString()
}
})
return view
}
}