0

With the following code I can click a button to send a string from one fragment (Fragment A) into a MainActivity. How would I retrieve the string from the MainActivity and display it on a fragment B all in one go? I would like the fragments to act synchronized; to have Fragment B update itself as soon as I click the button in Fragment A. I can't seem to find anything in SO on this.

Interface:

public interface OnDataListener {
    public void onDataReceived(String data);
}

Fragment A data listener:

OnDataListener mOnDataListener;

@Override
public void onAttach(Context context) {
    try{
        mOnDataListener = (OnDataListener) context;
        Log.d(TAG, "onAttach was called" + context);
    }catch (ClassCastException e){
        Log.e(TAG, "onAttach: ClassCastException: " + e.getMessage() );
    }
    super.onAttach(context);
}

Button logic in Fragment A's onCreateView:

button.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {

          String newTextString = editTextView.getText().toString();
          mOnDataListener.onDataReceived(newTextString);

        }
      });

MainActivity data receiver

public class MainActivity extends AppCompatActivity implements OnDataListener {


@Override
public void onDataReceived(String data) {

    Log.e(TAG, "MainActivity received this string " + data );

            }
}
Bread
  • 71
  • 1
  • 13

2 Answers2

1

Solution 1

In your MainActivity

@Override
public void onDataReceived(String data) {
   Log.e(TAG, "MainActivity received this string " + data );
   Bundle bundle = new Bundle();
   bundle.putString("edttext", data);
   FragmentB fragment = new FragmentB();
   fragment.setArguments(bundle);
   // Fragment Transaction method goes here
}

In your FragmentB Retrieve Data

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
   String strtext = getArguments().getString("edttext");    
   return inflater.inflate(R.layout.fragment, container, false);
}

Solution 2

You can put callback data to your global variable and use it at fragment transaction at the time of onClickListerner.

Solution 3

A) Create method in your FragmentB

public void changeText (String data) {
   textview.setText(data)
 }

B) And Pass Value From MainActivity

@Override
public void onDataReceived (String data) {
    myInterface.CallBack("Callbacked when onCreate method Created" + data);
    Log.d("Tiggered", "respond: ");
    FragmentManager manager = getFragmentManager();
    FragmentB fragmentB = (FragmentB) manager.findFragmentById(R.id.id_fragmentB);
    fragmentB.changeText(data);
}
Farid Haq
  • 3,728
  • 1
  • 21
  • 15
  • With the first approach I get a null object reference error in Fragment B – Bread Feb 22 '19 at 05:22
  • java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.os.Bundle.getString(java.lang.String)' on a null object reference – Bread Feb 22 '19 at 05:22
  • I don't how you did fragment transaction. please try other solution specially solution 3. Create method in your Fragment B , And pass value directly – Farid Haq Feb 22 '19 at 05:27
  • With solution 3 I get: on-static method 'CallBack(java.lang.String)' cannot be referenced from a static context – Bread Feb 22 '19 at 05:36
  • First you need to know inter communication fragment process. there have many online document about inter communication. There have also similar post please check it out https://stackoverflow.com/questions/13700798/basic-communication-between-two-fragments – Farid Haq Feb 22 '19 at 06:02
1

Solution 1: Using Callbacks

//this will work if your fragment instance is active so check viewpager offscreenpage limit

(You can also use solution 3 mentioned by Farid Haq, which do the same by doing work of activity itself)

Here, Activity implements callback OnDataUpdateListener

interface OnDataUpdateListener{
    void passDataToFragmentB(String data)
}

Activity code:

Fragment instanceFragmentB;
// intialise it somewhere in your activity
// or get from viewpager adapter

@Override
void passDataToFragmentB(String data){
    instanceFragmentB.onDataChange(data)
}

Fragment A code:

OnDataUpdateListener mOnDataUpdateListener;
onAttach(Activity activity){
    mOnDataUpdateListener=  (OnDataUpdateListener) activity
}

onViewCreated(){
    somebutton.onClick{
        mOnDataUpdateListener.passDataToFragmentB("someString")
    }
}

Fragment B code:

onDataChange(String data){
    //do your work with update data passed from fragment A  
}

Solution 2: Using EventBus or RxBus

//this will work if your fragment instance is active so check viewpager offscreenpage limit

Using event or rxbus, post new updated value on bus and make destination fragment observing that same value type.

Fragment A:

onViewCreated(){
    somebutton.onClick{
        EventBus.post("your data")
    }
}

Fragment B:

@Subsribe
void onDataChange(String data){
    //do your work with update data passed from fragment A  
}

Solution 3: Using ViewModel.

Take viewmodel with context of activity in all fragment and Wrap String with LiveData.

Whenever, string data is changed, just post new data on String Livedata object. All fragment observing that livedata will get updated value.

bhumik
  • 231
  • 2
  • 11
  • What do you mean by check offscreen page limit? I have it set to three – Bread Feb 27 '19 at 06:09
  • Approach 1 returns a null object reference error on the main acitivity line: instanceFragmentB.onDataChange(data) – Bread Feb 27 '19 at 06:10
  • 1
    On those approach, if you have offscreen page limit low like 1, and if you are changing some data on page 1 then page 3 fragment will not be on memory. so it will not receive any callback. as it will be initialized when user will scroll and come to 2nd or 3rd screen. .... For null error, check how you are getting instance of fragmentB, if you are using adapter try to get it from there. or better if you get current fragment from container and check it it's instance of FragmentB and then call onDataChange after casting. – bhumik Feb 27 '19 at 16:13
  • I went for the container approach and added it to your original answer, thanks for the help. There is more information here: https://stackoverflow.com/questions/15492717/get-fragment-dynamically-attached-to-framelayout – Bread Feb 27 '19 at 19:55