Sending Data from Nested Fragments to Parent Fragment

Sending data from nested fragments to parent fragment

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.

Communication between nested fragments in Android

Following Rahul Sharma's advice in the comments, I used interface callbacks to communicate up from the Child Fragment to the Parent Fragment and to the Activity. I also submitted this answer to Code Review. I am taking the non-answer there (at the time of this writing) to be a sign that there are no major problems with this design pattern. It seems to me to be consistent with the general guidance given in the official fragment communication docs.

Example project

The following example project expands the example given in the question. It has buttons that initiate upward communication from the fragments to the activity and from the Child Fragment to the Parent Fragment.

I set up the project layout like this:

Sample Image

Main Activity

The Activity implements the listeners from both fragments so that it can get messages from them.

Optional TODO: If the Activity wanted to initiate communication with the fragments, it could just get a direct reference to them and then call one of their public methods.

import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends AppCompatActivity implements ParentFragment.OnFragmentInteractionListener, ChildFragment.OnChildFragmentToActivityInteractionListener {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.parent_fragment_container, new ParentFragment());
ft.commit();
}

@Override
public void messageFromParentFragmentToActivity(String myString) {
Log.i("TAG", myString);
}

@Override
public void messageFromChildFragmentToActivity(String myString) {
Log.i("TAG", myString);
}
}

Parent Fragment

The Parent Fragment implements the listener from the Child Fragment so that it can receive messages from it.

Optional TODO: If the Parent Fragment wanted to initiate communication with the Child Fragment, it could just get a direct reference to it and then call one of its public methods.

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class ParentFragment extends Fragment implements View.OnClickListener, ChildFragment.OnChildFragmentInteractionListener {

// **************** start interesting part ************************

private OnFragmentInteractionListener mListener;

@Override
public void onClick(View v) {
mListener.messageFromParentFragmentToActivity("I am the parent fragment.");
}

@Override
public void messageFromChildToParent(String myString) {
Log.i("TAG", myString);
}

public interface OnFragmentInteractionListener {
void messageFromParentFragmentToActivity(String myString);
}

// **************** end interesting part ************************

@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_parent, container, false);
view.findViewById(R.id.parent_fragment_button).setOnClickListener(this);
return view;
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
Fragment childFragment = new ChildFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.replace(R.id.child_fragment_container, childFragment).commit();
}

@Override
public void onDetach() {
super.onDetach();
mListener = null;
}

}

Child Fragment

The Child Fragment defines listener interfaces for both the Activity and for the Parent Fragment. If the Child Fragment only needed to communicate with one of them, then the other interface could be removed.

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class ChildFragment extends Fragment implements View.OnClickListener {

// **************** start interesting part ************************

private OnChildFragmentToActivityInteractionListener mActivityListener;
private OnChildFragmentInteractionListener mParentListener;

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.child_fragment_contact_activity_button:
mActivityListener.messageFromChildFragmentToActivity("Hello, Activity. I am the child fragment.");
break;
case R.id.child_fragment_contact_parent_button:
mParentListener.messageFromChildToParent("Hello, parent. I am your child.");
break;
}
}

public interface OnChildFragmentToActivityInteractionListener {
void messageFromChildFragmentToActivity(String myString);
}

public interface OnChildFragmentInteractionListener {
void messageFromChildToParent(String myString);
}

@Override
public void onAttach(Context context) {
super.onAttach(context);

// check if Activity implements listener
if (context instanceof OnChildFragmentToActivityInteractionListener) {
mActivityListener = (OnChildFragmentToActivityInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnChildFragmentToActivityInteractionListener");
}

// check if parent Fragment implements listener
if (getParentFragment() instanceof OnChildFragmentInteractionListener) {
mParentListener = (OnChildFragmentInteractionListener) getParentFragment();
} else {
throw new RuntimeException("The parent fragment must implement OnChildFragmentInteractionListener");
}
}

// **************** end interesting part ************************

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_child, container, false);
view.findViewById(R.id.child_fragment_contact_activity_button).setOnClickListener(this);
view.findViewById(R.id.child_fragment_contact_parent_button).setOnClickListener(this);
return view;
}

@Override
public void onDetach() {
super.onDetach();
mActivityListener = null;
mParentListener = null;
}

}


Related Topics



Leave a reply



Submit