Sending data from nested fragments to parent fragment

AndroidAndroid FragmentsParameter PassingAndroid Nested-FragmentNavigation Architecture

Android Problem Overview


I have a Fragment FR1 that contains several Nested Fragments; FRa, FRb, FRc. These Nested Fragments are changed by pressing Buttons on FR1's layout. Each of the Nested Fragments have several input fields within them; which include things like EditTexts, NumberPickers, and Spinners. When my user goes through and fills in all the values for the Nested Fragments, FR1 (the parent fragment) has a submit button.

How can I then, retrieve my values from my Nested Fragments and bring them into FR1.

  1. All Views are declared and programmatically handled within each Nested Fragment.
  2. The parent Fragment, FR1 handles the transaction of the Nested Fragments.

I hope this question is clear enough and I am not sure if code is necessary to post but if someone feels otherwise I can do so.

EDIT 1:

Here is how I add my Nested Fragments:

tempRangeButton.setOnClickListener(new View.OnClickListener() {

		@Override
		public void onClick(View v) {
			
			getChildFragmentManager().beginTransaction()
					.add(R.id.settings_fragment_tertiary_nest, tempFrag)
					.commit();

		}
	});

	scheduleButton.setOnClickListener(new View.OnClickListener() {

		@Override
		public void onClick(View v) {
				
			getChildFragmentManager().beginTransaction()
					.add(R.id.settings_fragment_tertiary_nest, scheduleFrag)
					.commit();
		}
	});

	alertsButton.setOnClickListener(new View.OnClickListener() {

		@Override
		public void onClick(View v) {
				
			getChildFragmentManager().beginTransaction()
					.add(R.id.settings_fragment_tertiary_nest, alertsFrag)
					.commit();

		}
	});

	submitProfile.setOnClickListener(new View.OnClickListener() {

		@Override
		public void onClick(View v) {
			constructNewProfile();
		}
	});

where my constructNewProfile() method needs the values from my Nested Fragments.

public Fragment tempFrag = fragment_profile_settings_temperature
		.newInstance();
public Fragment scheduleFrag= fragment_profile_settings_schedules
			.newInstance();
public Fragment alertsFrag = fragment_profile_settings_alerts
		.newInstance();

The above refers to the fields of the parent fragment; and how they are initially instantiated.

Android Solutions


Solution 1 - Android

The best way is use an interface:

  1. Declare an interface in the nest fragment

     // Container Activity or Fragment must implement this interface
     public interface OnPlayerSelectionSetListener
     {
         public void onPlayerSelectionSet(List<Player> players_ist);
     }
    
  2. Attach the interface to parent fragment

     // In the child fragment.
     public void onAttachToParentFragment(Fragment fragment)
     {
         try
         {
             mOnPlayerSelectionSetListener = (OnPlayerSelectionSetListener)fragment;
    
         }
         catch (ClassCastException e)
         {
               throw new ClassCastException(
                   fragment.toString() + " must implement OnPlayerSelectionSetListener");
         }
     }
    
    
     @Override
     public void onCreate(Bundle savedInstanceState)
     {
         Log.i(TAG, "onCreate");
         super.onCreate(savedInstanceState);
    
         onAttachToParentFragment(getParentFragment());
    
         // ...
     }
                  
    
  3. Call the listener on button click.

     // In the child fragment.
     @Override
     public void onClick(View v)
     {
         switch (v.getId())
         {
             case R.id.tv_submit:
                 if (mOnPlayerSelectionSetListener != null)
                 {                
                      mOnPlayerSelectionSetListener.onPlayerSelectionSet(selectedPlayers);
                 }
                 break;
             }
         }
    
  4. Have your parent fragment implement the interface.

      public class Fragment_Parent extends Fragment implements Nested_Fragment.OnPlayerSelectionSetListener
      {
           // ...
           @Override
           public void onPlayerSelectionSet(final List<Player> players_list)
           {
                FragmentManager fragmentManager = getChildFragmentManager();
                SomeOtherNestFrag someOtherNestFrag = (SomeOtherNestFrag)fragmentManager.findFragmentByTag("Some fragment tag");
                //Tag of your fragment which you should use when you add
    
                if(someOtherNestFrag != null)
                {
                     // your some other frag need to provide some data back based on views.
                     SomeData somedata = someOtherNestFrag.getSomeData();
                     // it can be a string, or int, or some custom java object.
                }
           }
      }
    

Add Tag when you do fragment transaction so you can look it up afterward to call its method. FragmentTransaction

This is the proper way to handle communication between fragment and nest fragment, it's almost the same for activity and fragment. http://developer.android.com/guide/components/fragments.html#EventCallbacks

There is actually another official way, it's using activity result, but this one is good enough and common.

Solution 2 - Android

Instead of using interface, you can call the child fragment through below:

( (YourFragmentName) getParentFragment() ).yourMethodName();

Solution 3 - Android

The best way to pass data between fragments is using Interface. Here's what you need to do: In you nested fragment:

public interface OnDataPass {
    public void OnDataPass(int i);
}

OnDataPass dataPasser;

@Override
public void onAttach(Activity a) {
    super.onAttach(a);
    dataPasser = (OnDataPass) a;
}

public void passData(int i) {
    dataPasser.OnDataPass(i);
}

In your parent fragment:

public class Fragment_Parent extends Fragment implements OnDataPass {
...

    @Override
    public void OnDataPass(int i) {
        this.input = i;
    }

    btnOk.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            Fragment fragment = getSupportFragmentManager().findFragmentByTag("0");
            ((Fragment_Fr1) fragment).passData();
        }
    }

}

Solution 4 - Android

You can use share data between fragments.

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.
        });
    }
}

More Info ViewModel Architecture

Solution 5 - Android

You can use getChildFragmentManager() and find nested fragments, get them and run some methods to retrieve input values

Solution 6 - Android

Check for instanceOf before getting parent fragment which is better:

if (getParentFragment() instanceof ParentFragmentName) {
  getParentFragment().Your_parent_fragment_method();
}

Solution 7 - Android

Passing data between fragments can be done with FragmentManager. Starting with Fragment 1.3.0-alpha04, we can use setFragmentResultListener() and setFragmentResult() API to share data between fragments.

Official Documentation

Solution 8 - Android

Too late to ans bt i can suggest create EditText object in child fragment

EditText tx;

in Oncreateview Initialize it. then create another class for bridge like

public class bridge{
public static EditText text = null; 
}

Now in parent fragment get its refrence.

EditText childedtx = bridge.text;

now on click method get value

onclick(view v){
childedtx.getText().tostring();
}

Tested in my project and its work like charm.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTimothy FrischView Question on Stackoverflow
Solution 1 - AndroiduDevelView Answer on Stackoverflow
Solution 2 - AndroidRaja JawaharView Answer on Stackoverflow
Solution 3 - AndroidDariush MalekView Answer on Stackoverflow
Solution 4 - AndroidAhmad AghazadehView Answer on Stackoverflow
Solution 5 - Androidmichal.luszczukView Answer on Stackoverflow
Solution 6 - AndroidPankajView Answer on Stackoverflow
Solution 7 - AndroidNanzbzView Answer on Stackoverflow
Solution 8 - AndroidRachit VoheraView Answer on Stackoverflow