OnFragmentInteractionListener Implemented On Parent Fragment

If you're a Android Developer OnFragmentInteractionListener Interface is not a new thing for you.
It is the callback interface that comes with the auto-generated code, when you add a new fragment to your project in Android Studio.

If you have some exposure, you already know that it is used to pass messages to Activity from within the Fragment Code. Even if you don't have any experience in android it's not something hard to understand.
It is a pattern we always use in OOP languages for callbacks. You can know about it thoroughly, by reading my post, Callbacks With Interfaces Or Delegates. Read the Java part there.

Anyway in simple word, it's one class calling an interface method, and the other class is forced to implement that interface at creation. In most of the scenarios, this can be achieved by forcing to pass an interface implemented class through the constructor at creation.
But as android works on a life cycle approach, the interface implemented class object is passed through an event trigger, which is onAttach(Context). When you add a Fragment in Android Studio, the code inside this method also is automatically generated.

I'll simple explain what happens in there.

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

On attach get called when the Fragment is truly attached to it's container. At that point here it is checked whether the attached activity has implemented the OnFragmentInteractionListener interface. If the activity has implemented it, then it will be assigned to the instance variable of the Fragment, mListener. Then at any point where the Fragment wants to talk to the Activity, it can used the methods in OnFragmentInteractionListener interface.

Everything I explained above, most of you may know. Because Android Studio automatically implements most of the code for us, when we're adding a Fragment. So it was a very clear path to pass messages to the Activity from the Fragment.

Days were all good until, I started adding nested Fragments & I until I had a requirement for the Child Fragment, to talk to it's Parent Fragment. The auto implemented onAttach(Context) wasn't doing so much for me then.

The solution was very simple, though I had to search through internet and read about different approaches from different people. And following is the best approach I found to achieve what I wanted.
It's the magical method getParentFragment() which comes from the Fragment class.

For most of you, mentioning it may make it pretty clear, but for the ones who doesn't make sense I'll explain.
Following is a modified version of the onAttach(Context) method of the Child Fragment class.

     if (context instanceof OnChildFragmentInteractionByActivityListener) {  
       onChildFragmentInteractionByActivityListener = (OnChildFragmentInteractionByActivityListener) context;  
     } else {  
       throw new RuntimeException(context.toString()  
           + " OnChildFragmentInteractionByActivityListener must be implemented by the Activity.");  
     }  
   
     if (getParentFragment() instanceof OnChildFragmentInteractionByParentFragmentListener) {  
       onChildFragmentInteractionByParentFragmentListener = (OnChildFragmentInteractionByParentFragmentListener) getParentFragment();  
     } else {  
       throw new RuntimeException(" OnChildFragmentInteractionByParentFragmentListener must be implemented by the Parent Fragment.");  
     }  

It has the usual condition which comes with the auto-generated code, which is checking whether the Activity has implemented the callback listener interface. If the activity is has implemented the interface, context is cast and assigned to the instance variable. If not, an exception is thrown.

The same thing is done for the Parent Fragment, with one exception. Instead of using the contextgetParentFragment() method is used to get the Parent Fragment, who has added the Child Fragment into it's container.
Then the same way, it's assigned to the instance variable of the Child Fragment class.

Almost forgot.
There is one more place which needs your attention.
When you're adding the Child Fragment to the Parent Fragment, you have to use, getChildFragmentManager() instead of getFragmentManager().
If not, you won't be able to get Parent Fragment by calling getParentFragment() in the Child Fragment.
Then it will keep throwing the exception, "OnChildFragmentInteractionByParentFragmentListener must be implemented by the Parent Fragment." (The Runtime Exception I'm throwing from onAttach(Context) method of Child Fragment). Please pay attention to this.
Below is a code sample, how it is done in Parent Fragment.

  public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {  
     super.onViewCreated(view, savedInstanceState);  
   
     FragmentTransaction ft = getChildFragmentManager().beginTransaction();  
     ft.replace(R.id.frameLayout_ChildFragmentArea, new ChildFragment());  
     ft.commit();  
   }  

That's all I think.
In this post I've excluded some obvious minor details.
But if you need any clarifications, please be kind enough to ask them in the comments.

You can get a project of the full sample code by going to the following link. I've done the commits step by step, for your easy understanding.
GitHub

Cheers :)

Comments

Popular posts from this blog

WPF Dispatcher - Accessing UI Thread From Another Thread

Downgrade NuGet Packages - Visual Studio

Callbacks With Interfaces Or Delegates