Master the soul of Android Fragment development: in-depth analysis of Fragment (middle)


In the last article, we explored the core features, advantages, life cycle of Fragment, and how to use Fragment statically and dynamically. For interested friends, please go to: Master the soul of Android Fragment development: in-depth analysis of Fragment (I)


In this article, we will continue to explore Android Fragment in depth, including the following core topics:

Fragment communication

  • Fragment transfers data to activity
  • Activity transfers data to Fragment
  • Communication mode between fragments

Through comprehensive theoretical analysis, vivid example code and practical experience sharing, this article will help you thoroughly master the use skills of Fragment in Android application development, and improve code maintainability and user experience. Now, let's start this exciting Fragment journey together!


In Android applications, usually between Activity and Fragment Data communication is required between fragments. For this cross level communication, we have a variety of options, and each method has its own application scenarios. Next, let's disassemble them one by one.


I Fragment transfers data to activity


When Fragment needs to transfer data to host activity, there are several common ways:


1. Callback through interface


This is the most common and standard practice. We need to define an interface in Fragment and implement its methods in Activity. When Fragment needs to transfer data, just call the method in the interface.

Implementation details are as follows:

 //Define Interface public interface DataTransferInterface { void onDataReceived(String data); } //Fragment Implementation public class MyFragment extends Fragment { private DataTransferInterface dataTransferInterface; @Override public void onAttach(@NonNull Context context) { super.onAttach(context); if (context instanceof DataTransferInterface) { dataTransferInterface = (DataTransferInterface) context; } else { throw new RuntimeException("Activity must implement DataTransferInterface"); } } public void sendData(String data) { dataTransferInterface.onDataReceived(data); } } //Activity Implementation Interface public class MainActivity extends AppCompatActivity implements DataTransferInterface { @Override public void onDataReceived(String data) { //Processing data transferred from Fragment } }

2. Through ViewModel


If the application uses the ViewModel architecture component, it is also a good choice to share the ViewModel instance. Fragment can update data in ViewModel, Activity monitors these data changes and responds.


Step 1: Create the ViewModel class

 public class SharedViewModel extends ViewModel { private MutableLiveData<String> mMessage = new MutableLiveData<>(); public LiveData<String> getMessage() { return mMessage; } public void setMessage(String message) { mMessage.setValue(message); } }

stay SharedViewModel We define a private mMessage MutableLiveData object and a public getMessage() Method to get LiveData. setMessage() Method is used to set mMessage The value of.


Step 2: Create Fragment layout and class

 fragment_share_data.xml
 <? 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:orientation="vertical" android:padding="16dp"> <EditText android:id="@+id/edit_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter some text" /> <Button android:id="@+id/button_share" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Share Data" /> </LinearLayout> ShareDataFragment.java
 public class ShareDataFragment extends Fragment { private SharedViewModel viewModel; private EditText editText; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_share_data,  container, false); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view,  savedInstanceState); viewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class); editText = view.findViewById(R.id.edit_text); view.findViewById(R.id.button_share).setOnClickListener(v -> { viewModel.setMessage(editText.getText().toString()); }); } }

stay ShareDataFragment In, we first obtain SharedViewModel Instance of. Then, we onViewCreated() Method to set the button click event listener. When clicking the button, we will pass the text in EditText to the setMessage() method.


Step 3: Create Activity Layout and Class

 activity_main.xml
 <? 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:orientation="vertical" android:padding="16dp"> <FrameLayout android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <TextView android:id="@+id/text_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="18sp" /> </LinearLayout>
 MainActivity.java
 public class MainActivity extends AppCompatActivity { private TextView textView; private SharedViewModel viewModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.text_view); viewModel = new ViewModelProvider(this).get(SharedViewModel.class); viewModel.getMessage().observe(this,  message -> { textView.setText(message); }); if (savedInstanceState == null) { getSupportFragmentManager().beginTransaction() .replace(R.id.fragment_container,  new ShareDataFragment()) .commit(); } } }

stay MainActivity In, we first obtain SharedViewModel Instance of. Then, we observe the LiveData object in the ViewModel and update the text of the TextView when the data changes.


Finally, we onCreate() Method ShareDataFragment To the layout of the activity.

After running the sample application, you will see a fragment containing EditText and buttons. When you enter some text in EditText and click the "Share Data" button, the text will be passed to the ViewModel and displayed in the TextView of the Activity.


3. Through the Event Bus


Using event bus libraries (such as EventBus or RxBus) is also a solution. Fragment sends events, Activity registers to listen and handle events. This method is flexible, but it also adds complexity.


The following is a complete case of using the EventBus library to demonstrate data transfer from Fragment to Activity.


Step 1: Add EventBus dependency

First, we need to build.gradle Add the dependencies of the EventBus library to the file:

 dependencies { implementation 'org.greenrobot:eventbus:3.3.1' }

Step 2: Define the event class

We need to define an event class to transfer data between Fragment and Activity.

 public class MessageEvent { public final String message; public MessageEvent(String message) { this.message = message; } }

Step 3: Create Fragment layout and class

 fragment_share_data.xml
 <? 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:orientation="vertical" android:padding="16dp"> <EditText android:id="@+id/edit_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter some text" /> <Button android:id="@+id/button_share" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Share Data" /> </LinearLayout>
 ShareDataFragment.java
 public class ShareDataFragment extends Fragment { private EditText editText; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_share_data,  container, false); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view,  savedInstanceState); editText = view.findViewById(R.id.edit_text); view.findViewById(R.id.button_share).setOnClickListener(v -> { String message = editText.getText().toString(); EventBus.getDefault().post(new MessageEvent(message)); }); } @Override public void onStart() { super.onStart(); EventBus.getDefault().register(this); } @Override public void onStop() { super.onStop(); EventBus.getDefault().unregister(this); } }

stay ShareDataFragment We created a MessageEvent Object and send it to EventBus. In addition, we need to onStart() Register Fragment to EventBus in the onStop() Method.


Step 4: Create Activity Layout and Class

 activity_main.xml
 <? 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:orientation="vertical" android:padding="16dp"> <FrameLayout android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <TextView android:id="@+id/text_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="18sp" /> </LinearLayout>
 MainActivity.java
 public class MainActivity extends AppCompatActivity { private TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.text_view); if (savedInstanceState == null) { getSupportFragmentManager().beginTransaction() .replace(R.id.fragment_container,  new ShareDataFragment()) .commit(); } } @Override protected void onStart() { super.onStart(); EventBus.getDefault().register(this); } @Override protected void onStop() { super.onStop(); EventBus.getDefault().unregister(this); } @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) { textView.setText(event.message); } }

stay MainActivity In, we first onCreate() Method ShareDataFragment To the layout of the activity. Then, we onStart() Method, register the activity to EventBus, and onStop() Method.


Finally, we defined a onMessageEvent() Method, which will receive the MessageEvent Is called when. In this method, we will display the message passed from Fragment on the TextView.


Note that we used @Subscribe(threadMode = ThreadMode.MAIN) Annotations to ensure that the event processing logic is executed in the main thread, thereby avoiding potential thread safety problems.


After running the sample application, you will see a fragment containing EditText and buttons. When you enter some text in EditText and click the "Share Data" button, the text will be passed to the Activity and displayed in the TextView of the Activity.


II Activity transfers data to Fragment


When an activity needs to transfer data to a fragment, we have the following options:


1. Through Fragment arguments Bundle


This is an officially recommended practice. We can transfer data through Bundle when instantiating Fragment. Fragment can be found in onCreate() or onCreateView() Method to get arguments Bundle.


 //Create Bundle and add data Bundle bundle = new Bundle(); bundle.putString("key", "value"); //Instantiate Fragment and set arguments MyFragment fragment = new MyFragment(); fragment.setArguments(bundle); //Get data in Fragment String value = getArguments().getString("key");

2. Set data through FragmentManager


In addition to using arguments Bundle, we can also use FragmentManager to set data directly to the Fragment instance. However, this method needs to obtain the reference of Fragment instance in advance.


Suppose we have a MainActivity , which contains a ContentFragment We want to MainActivity Get some data from the FragmentManager Pass this data to ContentFragment


MainActivity.java

 import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import android.os.Bundle; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Suppose this is the data we want to pass to Fragment String dataToSend = "Hello,  Fragment! "; //Get FragmentManager instance FragmentManager fragmentManager = getSupportFragmentManager(); //Start Fragment Transaction FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); //Check whether the ContentFragment has been added. If not, add it if (fragmentManager.findFragmentByTag("ContentFragment") == null) { ContentFragment contentFragment = new ContentFragment(); //Pass data to Fragment through Bundle Bundle args = new Bundle(); args.putString("data",  dataToSend); contentFragment.setArguments(args); //Add Fragment to Transaction fragmentTransaction.add(R.id.fragment_container,  contentFragment,  "ContentFragment"); } //Commit Transaction fragmentTransaction.commit(); } }

activity_main.xml

 <FrameLayout xmlns:android=" http://schemas.android.com/apk/res/android " android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent"/>

ContentFragment.java

 import android.os.Bundle; import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class ContentFragment extends Fragment { public ContentFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater,  ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_content,  container, false); //Get data from Bundle Bundle args = getArguments(); if (args !=  null) { String data = args.getString("data"); //Display the passed data on the fragment UI TextView textView = view.findViewById(R.id.textview_data); textView.setText(data); } return view; } }

fragment_content.xml

 <LinearLayout xmlns:android=" http://schemas.android.com/apk/res/android " android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <TextView android:id="@+id/textview_data" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp" /> <!--  Other layout contents --> </LinearLayout>

In this example, MainActivity stay onCreate Method creates a String Type of data, and use the Bundle Pass it to ContentFragment Then, by FragmentTransaction take ContentFragment Added to the layout FrameLayout On. stay ContentFragment Of onCreateView In the method, we use getArguments Method to obtain the passed Bundle , extract data from and set it to TextView Is displayed on the.

This case shows how to use the FragmentManager and Bundle Data transfer. In practical applications, you can transfer more complex data structures as needed.


3. Through ViewModel


In the Android architecture component, ViewModel It is a class used to store and manage UI related data. When configuration changes (such as screen rotation), it still keeps data and will not be destroyed with the destruction of activities or fragments. use ViewModel It is easy to share data between activities and fragments, especially when communication between fragments is involved.

The following is the use of ViewModel stay Activity and Fragment A complete case of data transfer between.

Suppose we have a MainActivity , which uses a SharedViewModel To store some data and want to pass it to a ContentFragment

SharedViewModel.java

 import androidx.lifecycle.ViewModel; public class SharedViewModel extends ViewModel { private String data; public void setData(String data) { this.data = data; } public String getData() { return data; } }

MainActivity.java

 import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import androidx.lifecycle.ViewModelProvider; import android.os.Bundle; public class MainActivity extends AppCompatActivity { private SharedViewModel sharedViewModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sharedViewModel = new ViewModelProvider(this).get(SharedViewModel.class); //Suppose this is the data we want to pass to Fragment sharedViewModel.setData("Hello,  Fragment! "); //Get FragmentManager instance FragmentManager fragmentManager = getSupportFragmentManager(); //Start Fragment Transaction FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); //Check whether the ContentFragment has been added. If not, add it if (fragmentManager.findFragmentByTag("ContentFragment") == null) { ContentFragment contentFragment = new ContentFragment(); fragmentTransaction.add(R.id.fragment_container,  contentFragment,  "ContentFragment"); } //Commit Transaction fragmentTransaction.commit(); } }

ContentFragment.java

 import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class ContentFragment extends Fragment { private SharedViewModel sharedViewModel; public ContentFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater,  ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_content,  container, false); sharedViewModel = new ViewModelProvider(this).get(SharedViewModel.class); //Display the data in ViewModel on the UI of Fragment TextView textView = view.findViewById(R.id.textview_data); textView.setText(sharedViewModel.getData()); return view; } }

activity_main.xml

 <FrameLayout xmlns:android=" http://schemas.android.com/apk/res/android " android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent"/>

fragment_content.xml

 <LinearLayout xmlns:android=" http://schemas.android.com/apk/res/android " android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <TextView android:id="@+id/textview_data" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp" /> <!--  Other layout contents --> </LinearLayout>

In this example, MainActivity stay onCreate Method creates a SharedViewModel And set some data. Then it passes through FragmentTransaction take ContentFragment Added to the layout FrameLayout On.

stay ContentFragment Of onCreateView In the method, we use ViewModelProvider Obtained and MainActivity same SharedViewModel Instance, and obtain data from it, and display it in the TextView On.


use ViewModel The advantage is that even if Activity or Fragment Is destroyed and recreated, The data in the ViewModel is also not lost, which is useful when dealing with configuration changes such as screen rotation. In addition, ViewModel can also help to implement MVVM architecture pattern and improve code maintainability and testability.


III Communication between Fragments


For the communication between fragments, we have several options:


1. By sharing ViewModel


In Android development, The communication between fragments can be shared ViewModel realization. This method is particularly suitable for use ViewModel To maintain the continuity of data in configuration changes (such as screen rotation), and to share data among multiple fragments.

Here's how to use sharing ViewModel A complete case of communication between two fragments.

Suppose we have two fragments: FragmentA and FragmentB FragmentA Allow the user to enter some data, and then FragmentA This data is transferred through the shared ViewModel Pass to FragmentB


SharedViewModel.java

 import androidx.lifecycle.ViewModel; public class SharedViewModel extends ViewModel { private String data = ""; public void setData(String data) { this.data = data; } public String getData() { return data; } }

FragmentA.java

 import android.os.Bundle; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.navigation.Navigation; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; public class FragmentA extends Fragment { private SharedViewModel sharedViewModel; public FragmentA() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater,  ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_a,  container, false); sharedViewModel = new ViewModelProvider(this).get(SharedViewModel.class); EditText editText = view.findViewById(R.id.editTextData); Button button = view.findViewById(R.id.buttonSendData); button.setOnClickListener(new View. OnClickListener() { @Override public void onClick(View v) { String data = editText.getText().toString(); sharedViewModel.setData(data); //You can navigate FragmentB here Navigation.findNavController(v).navigate(R.id.action_fragmentA_to_fragmentB); } }); return view; } }

fragment_a.xml

 <LinearLayout xmlns:android=" http://schemas.android.com/apk/res/android " android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <EditText android:id="@+id/editTextData" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter data here"/> <Button android:id="@+id/buttonSendData" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Send Data"/> </LinearLayout>

FragmentB.java

 import android.os.Bundle; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class FragmentB extends Fragment { private SharedViewModel sharedViewModel; public FragmentB() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater,  ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_b,  container, false); sharedViewModel = new ViewModelProvider(this).get(SharedViewModel.class); TextView textView = view.findViewById(R.id.textViewData); textView.setText(sharedViewModel.getData()); return view; } }

fragment_b.xml

 <LinearLayout xmlns:android=" http://schemas.android.com/apk/res/android " android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <TextView android:id="@+id/textViewData" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp" /> <!--  Other layout contents --> </LinearLayout>

In this example, we created a SharedViewModel Class, which holds a String Data of type. stay FragmentA The data entered by the user is collected and stored in the SharedViewModel Medium. Then, navigate to the FragmentB


stay FragmentB , we also use ViewModelProvider obtain SharedViewModel And read data from it, and display it in the TextView On.

The advantage of this method is that even if the user FragmentA and FragmentB Switch between, or configuration changes such as screen rotation occur, SharedViewModel The data in will not be lost because ViewModel It is designed to be bound to the entire life cycle of UI controllers (such as Fragment or Activity).


2. Through the Event Bus


Using an event bus (such as EventBus) to communicate between fragments is a lightweight way, which allows different components to communicate asynchronously by publishing and subscribing to events. The following is a case of using EventBus to communicate between two fragments.


First, make sure you have added EventBus dependencies to your project. stay build.gradle Add the following dependencies to the file:

 dependencies { implementation 'org.greenrobot:eventbus:3.2.0' }

Suppose we have two fragments: FragmentA and FragmentB FragmentA Users are allowed to trigger an event, and then publish the event through EventBus. FragmentB Subscribe to this event and update the UI when the event is received.


EventBus initialization

stay Application Class to initialize EventBus and ensure that it is initialized when the application starts.

 import org.greenrobot.eventbus.EventBus; public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); EventBus.builder().addIndex(OptInIndex.class).installDefaultEventBus(); } }

Ensure that the AndroidManifest.xml Specified in MyApplication As your application The value of the label.

Define Events

Create a simple event class.

 import org.greenrobot.eventbus.Subscribe; public class DataEvent { public final String data; public DataEvent(String data) { this.data = data; } }

FragmentA.java

 import android.os.Bundle; import androidx.fragment.app.Fragment; import androidx.navigation.Navigation; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import org.greenrobot.eventbus.EventBus; public class FragmentA extends Fragment { private EventBus eventBus; public FragmentA() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater,  ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_a,  container, false); eventBus = EventBus.getDefault(); Button button = view.findViewById(R.id.buttonSendData); button.setOnClickListener(new View. OnClickListener() { @Override public void onClick(View v) { //Publish Events eventBus.post(new DataEvent("Data from FragmentA")); //Navigate to FragmentB, if necessary Navigation.findNavController(v).navigate(R.id.action_fragmentA_to_fragmentB); } }); return view; } @Override public void onStart() { super.onStart(); eventBus.register(this); } @Override public void onStop() public void onStop() { super.onStop(); eventBus.unregister(this); } }

FragmentB.java

 import android.os.Bundle; import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; public class FragmentB extends Fragment { private EventBus eventBus; private TextView textView; public FragmentB() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater,  ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_b,  container, false); textView = view.findViewById(R.id.textViewData); eventBus = EventBus.getDefault(); return view; } @Override public void onStart() { super.onStart(); eventBus.register(this); } @Override public void onStop() { super.onStop(); eventBus.unregister(this); } @Subscribe public void onEvent(DataEvent event) { //Update UI textView.setText(event.data); } }

Fragment_a.xml and fragment_b.xml

The layout files of these two fragments contain a button and a text view respectively, which are used to trigger events and display event data.

 <!--  fragment_a.xml --> <Button android:id="@+id/buttonSendData" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Send Data"/> <!--  fragment_b.xml --> <TextView android:id="@+id/textViewData" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp"/>

In this example, FragmentA Publish a DataEvent FragmentB Registered EventBus , and there is a method onEvent , which uses @Subscribe Notes to monitor DataEvent event. When FragmentB When it receives an event, it updates its TextView To display the data in the event.

Please note that when using EventBus, be sure to onStart Register EventBus in the onStop Method to avoid memory leaks. In addition, since EventBus is a global communication tool, attention should be paid to avoiding event conflicts between different components when using it.


3. Through mediation activity


In Android development, it is sometimes necessary to use mediation Activity To realize the communication between fragments. This usually happens when there is no direct connection between fragments, or it needs to be Activity To coordinate the interaction between fragments. The following is through mediation Activity A complete case of communication between two fragments.

Suppose we have two fragments: FragmentA and FragmentB FragmentA Allow the user to enter some data, and then call Activity The method in passes this data to the FragmentB

MainActivity.java

 import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import android.os.Bundle; import android.view.View; import android.widget.EditText; public class MainActivity extends AppCompatActivity implements FragmentA.OnDataPassListener { public interface OnDataPassListener { void onDataPass(String data); } private String receivedData = ""; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState == null) { FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); fragmentTransaction.add(R.id.fragment_container,  new FragmentA(), "FragmentA"); fragmentTransaction.commit(); } } public void receiveData(String data) { receivedData = data; updateFragmentB(); } private void updateFragmentB() { Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container); if (currentFragment instanceof FragmentB) { FragmentB fragmentB = (FragmentB) currentFragment; fragmentB.updateData(receivedData); } } }

FragmentA.java

 import android.os.Bundle; import androidx.fragment.app.Fragment; import androidx.appcompat.widget.AppCompatButton; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; public class FragmentA extends Fragment { private OnDataPassListener onDataPassListener; @Override public View onCreateView(LayoutInflater inflater,  ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_a,  container, false); final EditText editText = view.findViewById(R.id.editTextData); AppCompatButton button = view.findViewById(R.id.buttonSendData); button.setOnClickListener(new View. OnClickListener() { @Override public void onClick(View v) { String data = editText.getText().toString(); if (onDataPassListener !=  null) { onDataPassListener.onDataPass(data); } } }); return view; } @Override public void onAttach(Context context) { super.onAttach(context); if (context instanceof MainActivity. OnDataPassListener) { onDataPassListener = (MainActivity. OnDataPassListener) context; } else { throw new RuntimeException(context.toString() + " must implement OnDataPassListener"); } } @Override public void onDetach() { super.onDetach(); onDataPassListener = null; } }

FragmentB.java

 import android.os.Bundle; import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class FragmentB extends Fragment { private TextView textView; private MainActivity mainActivity; public FragmentB() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater,  ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_b,  container, false); textView = view.findViewById(R.id.textViewData); return view; } public void updateData(String data) { textView.setText(data); } @Override public void onAttach(Activity activity) { super.onAttach(activity); try { mainActivity = (MainActivity) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement MainActivity"); } } @Override public void onDetach() { super.onDetach(); mainActivity = null; } }

activity_main.xml

 <FrameLayout xmlns:android=" http://schemas.android.com/apk/res/android " android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent"/>

fragment_a.xml

 <LinearLayout xmlns:android=" http://schemas.android.com/apk/res/android " android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <EditText android:id="@+id/editTextData" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter data here"/> <Button android:id="@+id/buttonSendData" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Send Data"/> </LinearLayout>

fragment_b.xml

 <LinearLayout xmlns:android=" http://schemas.android.com/apk/res/android " android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <TextView android:id="@+id/textViewData" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp" /> <!--  Other layout contents --> </LinearLayout>

In this example, MainActivity Implemented a custom interface OnDataPassListener , this interface defines a method onDataPass For receiving from FragmentA Data transferred. FragmentA After the user enters the data and clicks the Send button, click the onDataPassListener.onDataPass(data); Call to pass data to MainActivity then, MainActivity By calling updateFragmentB() Method to pass data to FragmentB

stay FragmentB We defined a updateData Method to update the UI. MainActivity and FragmentB Communication between mainActivity Object implementation.

The advantage of this method is that, Activity It can be used as a mediator to coordinate the interaction between fragments, and can verify and process data at the same time. However, this approach may lead to increased code coupling, so it needs careful consideration in design.


4. Through the interface

In Android development, using the interface as the callback mechanism is a common way of communication between fragments. This method allows a fragment to request another fragment or activity to perform a specific operation when it needs to interact with another fragment or activity.

The following is the interface used in the FragmentA and FragmentB A complete case of communication between.

Suppose we have two fragments: FragmentA and FragmentB FragmentA Some data needs to be passed to FragmentB , but there is no direct reference between them. Therefore, we will FragmentB Define an interface in, and then let FragmentA Implement this interface to call when needed FragmentB Method.

FragmentB.java

 import android.os.Bundle; import androidx.fragment.app.Fragment; import androidx.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class FragmentB extends Fragment { private OnFragmentBActionListener listener; //Define an interface for callback public interface OnFragmentBActionListener { void onFragmentBAction(String data); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); //Set callback interface listener.onFragmentBAction("Initial data"); } @Override public View onCreateView(LayoutInflater inflater,  ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_b,  container, false); TextView textView = view.findViewById(R.id.textViewData); textView.setText("Waiting for data from Fragment A"); return view; } //Set the implementer of the callback interface public void setOnFragmentBActionListener(OnFragmentBActionListener listener) { this.listener = listener; } }

FragmentA.java

 import android.os.Bundle; import androidx.fragment.app.Fragment; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; public class FragmentA extends Fragment implements FragmentB.OnFragmentBActionListener { private EditText editText; private Button button; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_a,  container, false); editText = view.findViewById(R.id.editTextData); button = view.findViewById(R.id.buttonSendData); button.setOnClickListener(new View. OnClickListener() { @Override public void onClick(View v) { String data = editText.getText().toString(); //Call the FragmentB method to pass data onFragmentBAction(data); } }); return view; } @Override public void onFragmentBAction(String data) { //Implement the callback method of FragmentB here //Since FragmentA implements the interface of FragmentB, this method can be called directly here //But we need to hold the reference of FragmentB to pass data } }

MainActivity.java

 import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import android.os.Bundle; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); FragmentA fragmentA = new FragmentA(); fragmentTransaction.add(android. R.id.content, fragmentA); fragmentTransaction.commit(); //Assume FragmentB has been instantiated and added to Activity FragmentB fragmentB = (FragmentB) fragmentManager.findFragmentById(R.id.fragment_b); if (fragmentB !=  null) { //Set the callback interface of FragmentB fragmentB.setOnFragmentBActionListener(fragmentA); } } }

Layout file

The following are fragment_a.xml and fragment_b.xml Sample layout file for.

 <!--  fragment_a.xml --> <LinearLayout xmlns:android=" http://schemas.android.com/apk/res/android " android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <EditText android:id="@+id/editTextData" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter data here"/> <Button android:id="@+id/buttonSendData" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Send Data"/> </LinearLayout> <!--  fragment_b.xml --> <LinearLayout xmlns:android=" http://schemas.android.com/apk/res/android " android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <TextView android:id="@+id/textViewData" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp" /> <!--  Other layout contents --> </LinearLayout>

In this example, 'FragmentB' defines an interface 'OnFragmentBActionListener', which contains a method 'onFragmentBAction' to receive data` FragmentA ` implements this interface and calls this method when the user enters data and clicks the Send button.
In 'MainActivity', we instantiated 'FragmentA' and added it to the layout. At the same time, we call the 'setOnFragmentBActionListener' method of 'FragmentB' to pass' FragmentA 'as the implementer of the callback interface to' FragmentB '. Now, when 'FragmentA' needs to communicate with 'FragmentB', it can be realized by calling the 'onFragmentBAction' method.

Please note that in order for this example to work, you need to ensure that FragmentB Instance of already exists in MainActivity And has a method to set its callback interface. In addition, due to FragmentA Implemented FragmentB It can directly call the methods defined in the interface, but the premise is that it needs to hold FragmentB Reference to. In practical application, you can use the MainActivity Set this reference in, and then pass it to the fragment that needs it.


Conclusion:

These are some of the Fragment communication methods I summarized. Of course, the actual project also needs to be weighed and adjusted according to the specific situation. It is hoped that through this article, you can fully grasp the use skills of Fragment and improve your Android development ability.


  • twenty-one
    give the thumbs-up
  • step on
  • twenty-five
    Collection
    Think it's good? One click collection
  •  Reward
    Reward
  • zero
    comment
comment
Add Red Packet

Please fill in the red envelope greeting or title

individual

The minimum number of red packets is 10

element

The minimum amount of red packet is 5 yuan

Current balance three point four three element Go to recharge>
To be paid: ten element
Achieve 100 million technicians!
After receiving, you will automatically become a fan of the blogger and the red envelope owner rule
hope_wisdom
Red packet sent

Reward the author

W rain or shine w

Your encouragement will be the greatest impetus for my creation

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
Scan code for payment: ¥1
Obtaining
Scan code for payment

Your balance is insufficient, please change the scanning code to pay or Recharge

Reward the author

Paid in element
Payment with balance
Click to retrieve
Scan code for payment
Wallet balance zero

Deduction description:

1. The balance is the virtual currency of wallet recharge, and the payment amount is deducted at a ratio of 1:1.
2. The balance cannot be directly purchased and downloaded, but VIP, paid columns and courses can be purchased.

Balance recharge