Basic relationship between two fragments

I have activity - MainActivity . Inside this Activity , I have two fragments , both of which I created declaratively inside xml.

I am trying to pass a String text input by a user in Fragment A to a text view in Fragment B However, it is very difficult. Does anyone know how I can achieve this?

I know that a fragment can get a link to its activity using getActivity() . So what do I guess I'll start there?

+64
android android-fragments
Dec 04 '12 at 10:26
source share
11 answers

Take a look at the Android developers page: http://developer.android.com/training/basics/fragments/communicating.html#DefineInterface

In essence, you define the interface in your fragment A and allow your activities to implement this interface. Now you can call the interface method in your fragment, and your activity will receive an event. Now in your activity you can call the second fragment to update the text representation with the received value

Your activity implements your interface (see FragmentA below)

 public class YourActivity implements FragmentA.TextClicked{ @Override public void sendText(String text){ // Get Fragment B FraB frag = (FragB) getSupportFragmentManager().findFragmentById(R.id.fragment_b); frag.updateText(text); } } 

Fragment A defines the interface and calls the method if necessary

 public class FragA extends Fragment{ TextClicked mCallback; public interface TextClicked{ public void sendText(String text); } @Override public void onAttach(Activity activity) { super.onAttach(activity); // This makes sure that the container activity has implemented // the callback interface. If not, it throws an exception try { mCallback = (TextClicked) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement TextClicked"); } } public void someMethod(){ mCallback.sendText("YOUR TEXT"); } @Override public void onDetach() { mCallback = null; // => avoid leaking, thanks @Deepscorn super.onDetach(); } } 

Fragment B has a public way of doing something with text

 public class FragB extends Fragment{ public void updateText(String text){ // Here you have it } } 
+109
Dec 04
source share

Some other examples (and even documentation at the time of this writing) use the deprecated onAttach methods. Here is a completely updated example.

enter image description here

Notes

  • You do not want the fragments to communicate directly with each other or with the task. This connects them with certain activities and makes reuse difficult.
  • The solution is to create a callback listener interface that will be implemented in Activity. When a Fragment wants to send a message to another Fragment or its parent action, it can do this through the interface.
  • It is normal for an Activity to communicate directly with its child fragments of public methods.
  • Thus, Activity serves as a controller, passing messages from one fragment to another.

The code

MainActivity.java

 public class MainActivity extends AppCompatActivity implements GreenFragment.OnGreenFragmentListener { private static final String BLUE_TAG = "blue"; private static final String GREEN_TAG = "green"; BlueFragment mBlueFragment; GreenFragment mGreenFragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // add fragments FragmentManager fragmentManager = getSupportFragmentManager(); mBlueFragment = (BlueFragment) fragmentManager.findFragmentByTag(BLUE_TAG); if (mBlueFragment == null) { mBlueFragment = new BlueFragment(); fragmentManager.beginTransaction().add(R.id.blue_fragment_container, mBlueFragment, BLUE_TAG).commit(); } mGreenFragment = (GreenFragment) fragmentManager.findFragmentByTag(GREEN_TAG); if (mGreenFragment == null) { mGreenFragment = new GreenFragment(); fragmentManager.beginTransaction().add(R.id.green_fragment_container, mGreenFragment, GREEN_TAG).commit(); } } // The Activity handles receiving a message from one Fragment // and passing it on to the other Fragment @Override public void messageFromGreenFragment(String message) { mBlueFragment.youveGotMail(message); } } 

GreenFragment.java

 public class GreenFragment extends Fragment { private OnGreenFragmentListener mCallback; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_green, container, false); Button button = v.findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String message = "Hello, Blue! I'm Green."; mCallback.messageFromGreenFragment(message); } }); return v; } // This is the interface that the Activity will implement // so that this Fragment can communicate with the Activity. public interface OnGreenFragmentListener { void messageFromGreenFragment(String text); } // This method insures that the Activity has actually implemented our // listener and that it isn't null. @Override public void onAttach(Context context) { super.onAttach(context); if (context instanceof OnGreenFragmentListener) { mCallback = (OnGreenFragmentListener) context; } else { throw new RuntimeException(context.toString() + " must implement OnGreenFragmentListener"); } } @Override public void onDetach() { super.onDetach(); mCallback = null; } } 

BlueFragment.java

 public class BlueFragment extends Fragment { private TextView mTextView; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_blue, container, false); mTextView = v.findViewById(R.id.textview); return v; } // This is a public method that the Activity can use to communicate // directly with this Fragment public void youveGotMail(String message) { mTextView.setText(message); } } 

XML

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"> <!-- Green Fragment container --> <FrameLayout android:id="@+id/green_fragment_container" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:layout_marginBottom="16dp" /> <!-- Blue Fragment container --> <FrameLayout android:id="@+id/blue_fragment_container" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> </LinearLayout> 

fragment_green.xml

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:background="#98e8ba" android:padding="8dp" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/button" android:text="send message to blue" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> 

fragment_blue.xml

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:background="#30c9fb" android:padding="16dp" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/textview" android:text="TextView" android:textSize="24sp" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> 
+25
Oct 23 '17 at 2:48 on
source share

The best and recommended way is to use a generic ViewModel.

https://developer.android.com/topic/libraries/architecture/viewmodel#sharing

From a google doc:

 public class SharedViewModel extends ViewModel { private final MutableLiveData<Item> selected = new MutableLiveData<Item>(); public void select(Item item) { selected.setValue(item); } public LiveData<Item> getSelected() { return selected; } } public class MasterFragment extends Fragment { private SharedViewModel model; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class); itemSelector.setOnClickListener(item -> { model.select(item); }); } } public class DetailFragment extends Fragment { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class); model.getSelected().observe(this, { item -> // Update the UI. }); } } 

ps : two fragments never communicate directly

+9
Jun 05 '18 at 0:30
source share

Consider my 2 fragments A and B and suppose I need to transfer data from B to A.

Then create an interface in B and transfer the data to the main activity. Create another interface and pass the data to fragment A.

Share a small example:

Fragment A looks like

 public class FragmentA extends Fragment implements InterfaceDataCommunicatorFromActivity { public InterfaceDataCommunicatorFromActivity interfaceDataCommunicatorFromActivity; String data; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // TODO Auto-generated method stub return super.onCreateView(inflater, container, savedInstanceState); } @Override public void updateData(String data) { // TODO Auto-generated method stub this.data = data; //data is updated here which is from fragment B } @Override public void onAttach(Activity activity) { // TODO Auto-generated method stub super.onAttach(activity); try { interfaceDataCommunicatorFromActivity = (InterfaceDataCommunicatorFromActivity) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement TextClicked"); } } } 

FragmentB looks like

 class FragmentB extends Fragment { public InterfaceDataCommunicator interfaceDataCommunicator; @Override public void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); // call this inorder to send Data to interface interfaceDataCommunicator.updateData("data"); } public interface InterfaceDataCommunicator { public void updateData(String data); } @Override public void onAttach(Activity activity) { // TODO Auto-generated method stub super.onAttach(activity); try { interfaceDataCommunicator = (InterfaceDataCommunicator) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement TextClicked"); } } } 

Main activity

 public class MainActivity extends Activity implements InterfaceDataCommunicator { public InterfaceDataCommunicatorFromActivity interfaceDataCommunicatorFromActivity; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public void updateData(String data) { // TODO Auto-generated method stub interfaceDataCommunicatorFromActivity.updateData(data); } public interface InterfaceDataCommunicatorFromActivity { public void updateData(String data); } } 
+4
Oct 30 '13 at 9:59 on
source share

There is an easy way to implement communication between action fragments using architectural components. Data can be transferred between action fragments using ViewModel and LiveData.

Fragments involved in communication should use the same objects of the presentation model that are associated with the life cycle of the activity. The view model object contains a liveata object to which data is transmitted in one fragment, and the second fragment listens for changes in LiveData and receives data sent from the first fragment.

For a complete example, see http://www.zoftino.com/passing-data-between-android-fragments-using-viewmodel

+1
Aug 18 '18 at 15:58
source share

Learn "setTargetFragment ()"

Where startActivityForResult () establishes the relationship between the two actions, setTargetFragment () defines the caller / caller relationship between the two fragments.

0
Aug 18 '18 at 20:06
source share

I give my activity an interface that all fragments can then use. If you have many fragments in the same exercise, this saves a lot of code rewriting and is a cleaner / more modular solution than creating an individual interface for each fragment with similar functions. I also like how modular it is. The disadvantage is that some fragments will have access to functions that they do not need.

  public class MyActivity extends AppCompatActivity implements MyActivityInterface { private List<String> mData; @Override public List<String> getData(){return mData;} @Override public void setData(List<String> data){mData = data;} } public interface MyActivityInterface { List<String> getData(); void setData(List<String> data); } public class MyFragment extends Fragment { private MyActivityInterface mActivity; private List<String> activityData; public void onButtonPress(){ activityData = mActivity.getData() } @Override public void onAttach(Context context) { super.onAttach(context); if (context instanceof MyActivityInterface) { mActivity = (MyActivityInterface) context; } else { throw new RuntimeException(context.toString() + " must implement MyActivityInterface"); } } @Override public void onDetach() { super.onDetach(); mActivity = null; } } 
0
Aug 14 '19 at 15:33
source share

Update

Ignore this answer. Not that this does not work. But there are better methods. Moreover, Android strongly discourages direct communication between fragments. See white paper . Thanks to @Wahib Ul Haq for the tip.

Original answer

Well, you can create a private variable and setter in Fragment B and set the value from fragment A itself,

Fragmentb.java

 private String inputString; .... .... public void setInputString(String string){ inputString = string; } 

Fragmenta.java

 //go to fragment B FragmentB frag = new FragmentB(); frag.setInputString(YOUR_STRING); //create your fragment transaction object, set animation etc fragTrans.replace(ITS_ARGUMENTS) 

Or you can use Activity as you suggested.

-one
Dec 04 '12 at 10:33
source share

I recently created a library that uses annotations to generate a type customization template for you. https://github.com/zeroarst/callbackfragment

Here is an example. Click the TextView on DialogFragment to call the MainActivity onTextClicked , then grab an instance of MyFagment to interact with.

 public class MainActivity extends AppCompatActivity implements MyFragment.FragmentCallback, MyDialogFragment.DialogListener { private static final String MY_FRAGM = "MY_FRAGMENT"; private static final String MY_DIALOG_FRAGM = "MY_DIALOG_FRAGMENT"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getSupportFragmentManager().beginTransaction() .add(R.id.lo_fragm_container, MyFragmentCallbackable.create(), MY_FRAGM) .commit(); findViewById(R.id.bt).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MyDialogFragmentCallbackable.create().show(getSupportFragmentManager(), MY_DIALOG_FRAGM); } }); } Toast mToast; @Override public void onClickButton(MyFragment fragment) { if (mToast != null) mToast.cancel(); mToast = Toast.makeText(this, "Callback from " + fragment.getTag() + " to " + this.getClass().getSimpleName(), Toast.LENGTH_SHORT); mToast.show(); } @Override public void onTextClicked(MyDialogFragment fragment) { MyFragment myFragm = (MyFragment) getSupportFragmentManager().findFragmentByTag(MY_FRAGM); if (myFragm != null) { myFragm.updateText("Callback from " + fragment.getTag() + " to " + myFragm.getTag()); } } 

}

-one
May 30 '17 at 4:56 a.m.
source share

You can follow this example. It demonstrates the basic relationship between two fragments that transmit different data (text in a text editor) each time.

https://github.com/bitsabhi/DemoFragmentCommunications

-2
Sep 22 '15 at 15:05
source share



All Articles