KaliMa KaliMa - 1 month ago 14
Java Question

Communication between nested Fragments / Activities (both ways)

So normally in Activity + Fragment communication, in the onAttach method you can assign things to a Context such as a listener you've defined from a callback interface, and then use this to communicate / call functions implemented in the underlying Activity.

For example:

public class TestDialogFragment extends DialogFragment {
private static final String ARGUMENT_KEYWORD = "argument_keyword";
private String keyword;
private Button okButton;
private CallbackInterface callbackInterface;

public interface CallbackInterface {
void onCallbackInvoked(String keyword);
}

public static TestDialogFragment newInstance(String keyword) {
Bundle args = new Bundle();
TestDialogFragment fragment = new TestDialogFragment();
args.putString(ARGUMENT_KEYWORD, keyword);
fragment.setArguments(args);
return fragment;
}

@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
callbackInterface = (CallbackInterface) context;
}
catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement TestDialogFragment.CallbackInterface");
}
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
keyword = getArguments().getString(ARGUMENT_KEYWORD);
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View contentView = inflater.inflate(R.layout.dialogfragment_test, container, false);
okButton = (Button) contentView.findViewById(R.id.okButton);
okButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
callbackInterface.onCallbackInvoked(keyword);
getDialog().dismiss();
}
});
return contentView;
}
}


That's all good and well, but what if you're using nested Fragments (i.e. using getSupportFragmentManager() to launch the first Fragment but then using getChildFragmentManager() after that)?

For instance what if I have MainActivity -> FragmentA -> FragmentB -> FragmentC?


  1. Is there a way for me to pass my MainActivity's context all the way through to FragmentC so that FragmentC can trigger callbacks in MainActivity?

  2. What about the reverse? Is there a way I can call some function in FragmentC all the way back from MainActivity? Or do I have to do something like "MainActivity calls a function in FragmentA which calls the same function in FragmentB which calls the function in FragmentC that does the thing we want"?


Answer

Personally I have used an EventBus library (like this one) to accomplish this in a relatively clean way. That would be my first recommendation.

Staying within the Android framework:

If your goal is to communicate between components without tightly coupling them, one possibility is LocalBoadcastManager. You can essentially reproduce the functionality of an EventBus, however it's more cumbersome/less convenient to use:

  • You have to create numerous BroadcastReceiver classes and register them with IntentFilters.
  • All your messages are broadcasted Intents. This usually means lots of custom intent action strings littering the codebase. Any relevant data has to be packed into extras (whereas with EventBus you can use any object as the message).

You could also build a quasi-EventBus. Any component that receives messages will implement an interface for that message and register itself with some Singleton class. Anyone sending a message calls a method of the Singleton, who then iterates over any registered components to deliver the message.

Comments