6

I have two fragments, A and B let's say, where B contains a list. I would like to add a listener on Fragment B that notifies Fragment A of the chosen list item. I couldn't figure out how to initialize the listener in Fragment B since it is bad practice to pass arguments in fragment's constructors.

NOTE: Fragment B is contained inside Fragment A. i.e. I have a FrameLayout in Fragment A; and Fragment B covers that FrameLayout.

Any idea how I could do that?

riadrifai
  • 1,108
  • 2
  • 13
  • 26

3 Answers3

11

If you're saying that Fragment B is a child fragment of Fragment A (that is, you've added it to Fragment A using Fragment A's getChildFragmentManager()), then you can use the same approach that you use for Activity interfaces, but using getParentFragment() instead of getActivity().

For example:

Fragment B:

@Override
public void onAttach(Context context) {
    MyInterface myInterface = (MyInterface) getParentFragment();
}

Assuming that Fragment A implements MyInterface.

One convenience method we've used to avoid having to know whether a Fragment is hosted by another Fragment or an Activity is something like:

public static <T> getInterface(Class<T> interfaceClass, Fragment thisFragment) {
    final Fragment parent = thisFragment.getParentFragment();
    if (parent != null && interfaceClass.isAssignableFrom(parent)) {
        return interfaceClass.cast(parent);
    }

    final Activity activity = thisFragment.getActivity();
    if (activity != null && interfaceClass.isAssignableFrom(activity)) {
        return interfaceClass.cast(activity);
    }

    return null;
}

Then you can just use:

MyInterface myInterface = getInterface(MyInterface.class, this);

and it doesn't matter whether Fragment B is hosted as a child Fragment or in an Activity directly.

Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274
5

A better approach for this situation, since what you want to do is communication between fragments, is to use an interface. You want to notify A when B has changed. This should be done through the parent activity. Here is the android documentation on the topic: https://developer.android.com/training/basics/fragments/communicating.html.

The gist of it is that you want to define an interface with a method called OnItemSelected (you can name it whatever you want). In B, you want a reference to this interface. When an item is selected, call your new OnItemSelected method. Implement this interface in the parent activity of the two fragments. In the implementation, you can put whatever code you want to modify A.

An example

CommunicationInterface

public interface CommunicationInterface {
    public void onItemSelected(int position);
}

FragmentB

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    CommunicationInterface myInterface = (CommunicationInterface) getActivity();
    // What ever else you want here
}

@Override
public void onListItemClick(ListView l, View v, int position, long id) {
    // Send the event to the host activity
    myInterface.onItemSelected(position);
}

MainActivity

public class MainActivity extends FragmentActivity implements CommunicationInterface {
    // What ever other code you have

    @Override
    public void onItemSelected(int position) {
        FragmentA fragA = (FragmentA)
        getSupportFragmentManager().findFragmentById(R.id.fragment_a);

        // Code to interact with Fragment A
    }
JPal
  • 59
  • 4
  • 1
    Yes I have seen this and tried it. But the thing is in my case, fragment B is inside fragment A, and I will be having more fragments later, so it is a hassle to implement all the interfaces from the main activity, which is why I'm searching for a new approach. – riadrifai Aug 25 '16 at 22:42
0

Checkout the contract pattern https://gist.github.com/JakeWharton/2621173

If you are using multiple fragment, you dont have do it for every fragment, just add it to your BaseActivity if you have one.

This example shows the communication between activity and fragment. But for nested fragment you can replace the acitivy with getParentFragment();

rahul.ramanujam
  • 5,608
  • 7
  • 34
  • 56