Create BaseFragment and extend this Fragment in ChildFragment

I've implemented this structure where you can have your BaseFragment layout appear in your ChildFragment layout. Basically, I've used ViewStub to implement the solution. VewStub is kinda placeholder layout. It will be created when xml is loaded and then you can replace the ViewStub with designated view hierarchy. I'm gonna use self-explanatory variable names to avoid additional explanation :). You can check out the sample project on GitHub.

fragment_core.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ViewStub
        android:id="@+id/child_fragment_will_be_displayed_here"
        android:layout_width="match_parent"
        android:layout_height="100dp">
    </ViewStub>


    <TextView
        android:id="@+id/core_fragment_text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/child_fragment_content_holder"/>

</RelativeLayout>

FragmentCore.class

   public abstract class FragmentCore extends Fragment {

    public FragmentCore() {
        // Required empty public constructor
    }

     protected TextView mTextViewInCoreActivity;

     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
                              Bundle savedInstanceState) {
         View coreFragmentView = inflater.inflate(R.layout.fragment_core, container, false);
         mTextViewInCoreActivity = coreFragmentView.findViewById(R.id.core_fragment_text_view);
         loadLayoutFromResIdToViewStub(coreFragmentView, container);
         return coreFragmentView;
     }

     public abstract void loadLayoutFromResIdToViewStub(View rootView,ViewGroup container);

 }

fragment_child.xml

 <FrameLayout
    android:layout_width="match_parent"
    android:layout_height="100dp"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/child_fragment_content_holder">

    <TextView
        android:id="@+id/child_fragment_text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</FrameLayout>

FragmentChild.class

    public class FragmentChild extends FragmentCore {


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }

    @Override
    public void loadLayoutFromResIdToViewStub(View coreFragmentView, ViewGroup container){

        setRetainInstance(true);

        if (container != null) {
            container.removeAllViews();
        }

        ViewStub stub = coreFragmentView.findViewById(R.id.child_fragment_will_be_displayed_here);
        stub.setLayoutResource(R.layout.fragment_child);
        stub.inflate();

        TextView childFragmentTextView = coreFragmentView.findViewById(R.id.child_fragment_text_view);

        mTextViewInCoreActivity.setText("Core (Parent) Fragment TextView is accessible");
        childFragmentTextView.setText("Child Fragment TextView is accessible");
    }

}

ABSTRACT CLASS APPROACH ?

I understand what you are trying to do (inheritance) here. But as pointed out by @hobokent, just by inheriting the BaseClass will not include your childView layout on top of BaseClass Layout. There are many ways to conquer this problem

Let's look into this solution.

  • Create an abstract class which will extend the Fragment Class (This will be BaseClass).

  • Make an abstract method which will return a layout.

  • Provide implementation for your abstract method in the ChildClass.

Here is the code snippet.

BaseClass

public abstract class BasicFragment extends Fragment {

  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
  }

  public View onCreateView(LayoutInflater inflater,ViewGroup parent, Bundle savedInstanseState)
   {
      View view = provideYourFragmentView(inflater,parent,savedInstanseState);
      return view;
   }

   public abstract View provideYourFragmentView(LayoutInflater inflater,ViewGroup parent, Bundle savedInstanceState);

}

ChildClass

public class ImageFragment extends BasicFragment{

  @Override
  public View provideYourFragmentView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.image_fragment,parent,false);

    //Now specific components here (you can initialize Buttons etc)

    return view;
   }


}

For your specific requirement, if you want the same layout to appear in child class layout. You can make a method which will return a layout and maybe in your child layout you make a placeholder for BaseClass Layout and add the BaseClass layout in childLayout using child.add(base_layout). Again it is just another design solution.
You can also put a common layout in Activity layout and Add fragment in Activity placeholder for the fragment. There are so many possible solutions.

I don't have any code specific to your requirement but here is the example where I have implemented this approach for TabLayout, where each tab is a different Fragment with a different layout.
Github full code sample.


Extending the Fragment won't include the views, those views are from which layout you inflate, therefore you won't see the text views from fragment_base in your Child Fragment.

It might benefit you to instead create and use custom views/compound views that you can then reuse in your other fragments.

You can read up on Compound Views here:

https://medium.com/@Sserra90/android-writing-a-compound-view-1eacbf1957fc