All communications between Fragments must go via an Activity. Fragments CANNOT communicate with each other without an Activity.
Additional Resources
In this sample, we have a MainActivity
that hosts two fragments, SenderFragment
and ReceiverFragment
, for sending and receiving a message
(a simple String in this case) respectively.
A Button in SenderFragment
initiates the process of sending the message. A TextView in the ReceiverFragment
is updated when the message is received by it.
Following is the snippet for the MainActivity with comments explaining the important lines of code:
// Our MainActivity implements the interface defined by the SenderFragment. This enables
// communication from the fragment to the activity
public class MainActivity extends AppCompatActivity implements SenderFragment.SendMessageListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
/**
* This method is called when we click on the button in the SenderFragment
* @param message The message sent by the SenderFragment
*/
@Override
public void onSendMessage(String message) {
// Find our ReceiverFragment using the SupportFragmentManager and the fragment's id
ReceiverFragment receiverFragment = (ReceiverFragment)
getSupportFragmentManager().findFragmentById(R.id.fragment_receiver);
// Make sure that such a fragment exists
if (receiverFragment != null) {
// Send this message to the ReceiverFragment by calling its public method
receiverFragment.showMessage(message);
}
}
}
The layout file for the MainActivity
hosts two fragments inside a LinearLayout :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.naru.fragmentcommunication.MainActivity">
<fragment
android:id="@+id/fragment_sender"
android:name="com.naru.fragmentcommunication.SenderFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
tools:layout="@layout/fragment_sender" />
<fragment
android:id="@+id/fragment_receiver"
android:name="com.naru.fragmentcommunication.ReceiverFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
tools:layout="@layout/fragment_receiver" />
</LinearLayout>
The SenderFragment
exposes an interface SendMessageListener
that helps the MainActivity
know when Button in the SenderFragment
was clicked.
Following is the code snippet for the SenderFragment
explaining the important lines of code:
public class SenderFragment extends Fragment {
private SendMessageListener commander;
/**
* This interface is created to communicate between the activity and the fragment. Any activity
* which implements this interface will be able to receive the message that is sent by this
* fragment.
*/
public interface SendMessageListener {
void onSendMessage(String message);
}
/**
* API LEVEL >= 23
* <p>
* This method is called when the fragment is attached to the activity. This method here will
* help us to initialize our reference variable, 'commander' , for our interface
* 'SendMessageListener'
*
* @param context
*/
@Override
public void onAttach(Context context) {
super.onAttach(context);
// Try to cast the context to our interface SendMessageListener i.e. check whether the
// activity implements the SendMessageListener. If not a ClassCastException is thrown.
try {
commander = (SendMessageListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ "must implement the SendMessageListener interface");
}
}
/**
* API LEVEL < 23
* <p>
* This method is called when the fragment is attached to the activity. This method here will
* help us to initialize our reference variable, 'commander' , for our interface
* 'SendMessageListener'
*
* @param activity
*/
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Try to cast the context to our interface SendMessageListener i.e. check whether the
// activity implements the SendMessageListener. If not a ClassCastException is thrown.
try {
commander = (SendMessageListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ "must implement the SendMessageListener interface");
}
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
// Inflate view for the sender fragment.
View view = inflater.inflate(R.layout.fragment_receiver, container, false);
// Initialize button and a click listener on it
Button send = (Button) view.findViewById(R.id.bSend);
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Sanity check whether we were able to properly initialize our interface reference
if (commander != null) {
// Call our interface method. This enables us to call the implemented method
// in the activity, from where we can send the message to the ReceiverFragment.
commander.onSendMessage("HELLO FROM SENDER FRAGMENT!");
}
}
});
return view;
}
}
The layout file for the SenderFragment
:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<Button
android:id="@+id/bSend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SEND"
android:layout_gravity="center_horizontal" />
</LinearLayout>
The ReceiverFragment
is simple and exposes a simple public method to updates its TextView. When the MainActivity
receives the message from the SenderFragment
it calls this public method of the ReceiverFragment
Following is the code snippet for the ReceiverFragment
with comments explaining the important lines of code :
public class ReceiverFragment extends Fragment {
TextView tvMessage;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
// Inflate view for the sender fragment.
View view = inflater.inflate(R.layout.fragment_receiver, container, false);
// Initialize the TextView
tvMessage = (TextView) view.findViewById(R.id.tvReceivedMessage);
return view;
}
/**
* Method that is called by the MainActivity when it receives a message from the SenderFragment.
* This method helps update the text in the TextView to the message sent by the SenderFragment.
* @param message Message sent by the SenderFragment via the MainActivity.
*/
public void showMessage(String message) {
tvMessage.setText(message);
}
}
The layout file for the ReceiverFragment
:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/tvReceivedMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Waiting for message!" />
</LinearLayout>