Fragment Inside Fragment

AndroidAndroid FragmentsAndroid Nested-Fragment

Android Problem Overview


I need help regarding working on fragment inside fragment, actually I am facing a problem on pressing back button. Application Main screen has buttons and pressing on each button view replace with new fragment(and that fragment contain inside another fragment), dynamically adding/replacing fragment is working fine, by pressing button1 fragment replaced, same happens when pressing button, but if I press the button again, got an exception:

"Duplicate id 0x7f05000a, tag null, or parent id 0x7f050009 with
another fragment for com........ fragmentname"

means fragment or inner fragments are already added and I am trying to add them again, anybody has idea how to work with fragment inside fragment and moving back and forth without any problem, thanks for the support.

MainActivity, where fragments are dynamical added and replaced.

public class FragmentInsideFragmentTestActivity extends Activity {

    private Button button1;
    private Button button2;
    private Button button3;
    private Button button4;


    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        button1 =(Button) this.findViewById(R.id.button1);
        button1.setOnClickListener(new View.OnClickListener() {
           public void onClick(View view) {
               onButtonClick(view);
            }
        });

        button2 =(Button) this.findViewById(R.id.button2);
        button2.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                onButtonClick(view);
            }
        });

        button3 =(Button) this.findViewById(R.id.button3);
        button3.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
               onButtonClick(view);
            }
        });

        button4 =(Button) this.findViewById(R.id.button4);
        button4.setOnClickListener(new View.OnClickListener() {
           public void onClick(View view) {
               onButtonClick(view);
           }
        });
    }

    public void onButtonClick(View v) {
        Fragment fg;

        switch (v.getId()) {
           case R.id.button1:
                   fg=FirstFragment.newInstance();
                   replaceFragment(fg);
                   break;
           case R.id.button2:
                   fg=SecondFragment.newInstance();
                   replaceFragment(fg);
                   break;
           case R.id.button3:
                   fg=FirstFragment.newInstance();
                   replaceFragment(fg);
                   break;
           case R.id.button4:
                   fg=SecondFragment.newInstance();
                   replaceFragment(fg);
                   break;
        }
    }

    private void replaceFragment(Fragment newFragment) {
       FragmentTransaction trasection = getFragmentManager().beginTransaction();

        if(!newFragment.isAdded()) {
            try {
                //FragmentTransaction trasection =
                getFragmentManager().beginTransaction();
                trasection.replace(R.id.linearLayout2, newFragment);
                trasection.addToBackStack(null);
                trasection.commit();
            } catch (Exception e) {
                // TODO: handle exception
                // AppConstants.printLog(e.getMessage());
            } else {
                trasection.show(newFragment);
            }
        }
    }

Here is Layout: main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button1" />

        <Button
            android:id="@+id/button2"
            android:text="Button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <Button
            android:id="@+id/button3"
            android:text="Button3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <Button
            android:id="@+id/button4"
            android:text="Button4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/linearLayout2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" />
</LinearLayout>

Hope I tried to clear my problem.

Android Solutions


Solution 1 - Android

AFAIK, fragments cannot hold other fragments.


UPDATE

With current versions of the Android Support package -- or native fragments on API Level 17 and higher -- you can nest fragments, by means of getChildFragmentManager(). Note that this means that you need to use the Android Support package version of fragments on API Levels 11-16, because even though there is a native version of fragments on those devices, that version does not have getChildFragmentManager().

Solution 2 - Android

enter image description here

I needed some more context, so I made an example to show how this is done. The most helpful thing I read while preparing was this:

#Activity

activity_main.xml

Add a FrameLayout to your activity to hold the parent fragment.

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

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Activity"/>

    <FrameLayout
        android:id="@+id/parent_fragment_container"
        android:layout_width="match_parent"
        android:layout_height="200dp"/>

 </LinearLayout>

MainActivity.java

Load the parent fragment and implement the fragment listeners. (See fragment communication.)

import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;

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

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

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

    @Override
    public void messageFromParentFragment(Uri uri) {
        Log.i("TAG", "received communication from parent fragment");
    }

    @Override
    public void messageFromChildFragment(Uri uri) {
        Log.i("TAG", "received communication from child fragment");
    }
}

#Parent Fragment

fragment_parent.xml

Add another FrameLayout container for the child fragment.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:layout_margin="20dp"
              android:background="#91d0c2">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Parent fragment"/>

    <FrameLayout
        android:id="@+id/child_fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </FrameLayout>

</LinearLayout>

ParentFragment.java

Use getChildFragmentManager in onViewCreated to set up the child fragment.

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;    

public class ParentFragment extends Fragment {

    private OnFragmentInteractionListener mListener;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_parent, container, false);
    }

    @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 onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnFragmentInteractionListener) {
            mListener = (OnFragmentInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

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

    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        void messageFromParentFragment(Uri uri);
    }
}

#Child Fragment

fragment_child.xml

There is nothing special here.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:layout_margin="20dp"
              android:background="#f1ff91">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Child fragment"/>
</LinearLayout>

ChildFragment.java

There is nothing too special here, either.

import android.support.v4.app.Fragment;
    
public class ChildFragment extends Fragment {

    private OnFragmentInteractionListener mListener;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_child, container, false);
    }

    @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 void onDetach() {
        super.onDetach();
        mListener = null;
    }


    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        void messageFromChildFragment(Uri uri);
    }
}

#Notes

  • The support library is being used so that nested fragments can be used before Android 4.2.

Solution 3 - Android

Since Android 4.2 (API 17) nested fragments become available http://developer.android.com/about/versions/android-4.2.html#NestedFragments

To place fragment inside other fragment use getChildFragmentManager()

It also available in support library!

Solution 4 - Android

Fragments can be added inside other fragments but then you will need to remove it from parent Fragment each time when onDestroyView() method of parent fragment is called. And again add it in Parent Fragment's onCreateView() method.

Just do like this :

@Override
	public void onDestroyView()
	{
                FragmentManager mFragmentMgr= getFragmentManager();
		FragmentTransaction mTransaction = mFragmentMgr.beginTransaction();
                Fragment childFragment =mFragmentMgr.findFragmentByTag("qa_fragment")
		mTransaction.remove(childFragment);
		mTransaction.commit();
		super.onDestroyView();
	}

Solution 5 - Android

you can use getChildFragmentManager() function.

example:

Parent fragment :

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    rootView = inflater.inflate(R.layout.parent_fragment, container,
            false);


    }

    //child fragment 
    FragmentManager childFragMan = getChildFragmentManager();
    FragmentTransaction childFragTrans = childFragMan.beginTransaction();
    ChildFragment fragB = new ChildFragment ();
    childFragTrans.add(R.id.FRAGMENT_PLACEHOLDER, fragB);
    childFragTrans.addToBackStack("B");
    childFragTrans.commit();        


    return rootView;
}

Parent layout (parent_fragment.xml):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white">



    <FrameLayout
        android:id="@+id/FRAGMENT_PLACEHOLDER"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>




</LinearLayout>

Child Fragment:

public class ChildFragment extends Fragment implements View.OnClickListener{

    View v ;
    @Override
    public View onCreateView(LayoutInflater inflater,
                             @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        View rootView = inflater.inflate(R.layout.child_fragment, container, false);


        v = rootView;


        return rootView;
    }



    @Override
    public void onClick(View view) {


    }


} 

Solution 6 - Android

I solved this problem. You can use Support library and ViewPager. If you don't need swiping by gesture you can disable swiping. So here is some code to improve my solution:

public class TestFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.frag, container, false);
    final ArrayList<Fragment> list = new ArrayList<Fragment>();

    list.add(new TrFrag());
    list.add(new TrFrag());
    list.add(new TrFrag());

    ViewPager pager = (ViewPager) v.findViewById(R.id.pager);
    pager.setAdapter(new FragmentPagerAdapter(getChildFragmentManager()) {
        @Override
        public Fragment getItem(int i) {
            return list.get(i);
        }

        @Override
        public int getCount() {
            return list.size();
        }
    });
    return v;
}
}

P.S.It is ugly code for test, but it improves that it is possible.

P.P.S Inside fragment ChildFragmentManager should be passed to ViewPagerAdapter

Solution 7 - Android

It's nothing complicated. We cannot use getFragmentManager() here. For using Fragments inside a Fragment, we use getChildFragmentManager(). Rest will be the same.

Solution 8 - Android

Use getChildFragmentManager(), follow the link : Nested Fragment

Solution 9 - Android

You can add FrameLayout to the fragment and replace it with another fragment when it initializes.

This way , you could consider the other fragment to be inside the first fragment.

Solution 10 - Android

Curently in nested fragment, the nested one(s) are only supported if they are generated programmatically! So at this time no nested fragment layout are supported in xml layout scheme!

Solution 11 - Android

There is no support for MapFragment, Android team says is working on it since Android 3.0. Here more information about the issue But what you can do it by creating a Fragment that returns a MapActivity. Here is a code example. Thanks to inazaruk:

How it works :

  • MainFragmentActivity is the activity that extends FragmentActivity and hosts two MapFragments.
  • MyMapActivity extends MapActivity and has MapView.
  • LocalActivityManagerFragment hosts LocalActivityManager.
  • MyMapFragment extends LocalActivityManagerFragment and with help of TabHost creates internal instance of MyMapActivity.

If you have any doubt please let me know

Solution 12 - Android

That may help those who works on Kotlin you can use extension function so create a kotlin file let's say "util.kt" and add this piece of code

fun Fragment.addChildFragment(fragment: Fragment, frameId: Int) {

    val transaction = childFragmentManager.beginTransaction()
    transaction.replace(frameId, fragment).commit()
}

Let's say this is the class of the child

class InputFieldPresentation: Fragment()
{
    var views: View? = null
    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        views = inflater!!.inflate(R.layout.input_field_frag, container, false)
        return views
    }

    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        ...
    }
    ...
}

Now you can add the children to the father fragment like this

 FatherPresentation:Fragment()
{
  ...

    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val fieldFragment= InputFieldPresentation()
        addChildFragment(fieldFragment,R.id.fragmet_field)
    }
...
}

where R.id.fragmet_field is the id of the layout which will contain the fragment.This lyout is inside the father fragment of course. Here is an example

father_fragment.xml:

<LinearLayout android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
        
    ...

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:id="@+id/fragmet_field"
            android:orientation="vertical"
            >
        </LinearLayout>
    ...

    </LinearLayout>

Solution 13 - Android

Hi I solved this problem by putting per Fragment into distinct layout.And I made just related Layout visible and made the others visibilities gone.

I mean:

<?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent">

     <LinearLayout android:id="@+id/linearLayout1"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:orientation="horizontal">
           <Button android:layout_width="wrap_content"
                   android:id="@+id/button1"
                   android:layout_height="wrap_content"
                   android:text="Button1"></Button>
           <Button android:text="Button2"
                   android:id="@+id/button2"
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"></Button>
           <Button android:text="Button3"
                   android:id="@+id/button3"
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"></Button>
           <Button android:text="Button4"
                   android:id="@+id/button4"
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"></Button>
   </LinearLayout>
   <LinearLayout android:layout_width="full_screen"
              android:layout_height="0dp"
              android:layout_weight="1"
              android:id="action_For_Button1"
              android:visibility="visible">
                    <Fragment android:layout_width="full_screen"
                              android:layout_height="full_screen"
                              android:id="fragment1"
                                        .
                                        .
                                        .
             / >
     </LinearLayout>

     <LinearLayout android:layout_width="full_screen"
              android:layout_height="0dp"
              android:id="action_For_Button1"
              android:layout_weight="1"
              android:visibility="gone">
                       <Fragment android:layout_width="full_screen"
                                 android:layout_height="full_screen"
                                 android:id="fragment2"
                                           .
                                           .
                                           .
             / >
        </LinearLayout>
                     .
                     .
                     .
        </LinearLayout>

I assumed that you will open your page as button 1 is clicked.You can control your fragment's visibilities on click action.You can make related Layout visible and the others gone and by Fragment Manager you can take your fragment.This approach worked for me.And since view that has visibility:gone is invisible, and it doesn't take any space for layout purposes I think this approach does not cause any space problem.

P.S:I just tried to explain my solution code may have syntax mistakes or uncompleted structure.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionIjaz AhmedView Question on Stackoverflow
Solution 1 - AndroidCommonsWareView Answer on Stackoverflow
Solution 2 - AndroidSuragchView Answer on Stackoverflow
Solution 3 - AndroidNikView Answer on Stackoverflow
Solution 4 - AndroidNapoleanView Answer on Stackoverflow
Solution 5 - AndroidS.M_EmamianView Answer on Stackoverflow
Solution 6 - AndroidVetalllView Answer on Stackoverflow
Solution 7 - AndroidWijay SharmaView Answer on Stackoverflow
Solution 8 - AndroidHacker CelluloidView Answer on Stackoverflow
Solution 9 - AndroidLoveBigPizzaView Answer on Stackoverflow
Solution 10 - AndroidAndrea BellittoView Answer on Stackoverflow
Solution 11 - AndroidrallatView Answer on Stackoverflow
Solution 12 - AndroidDINA TAKLITView Answer on Stackoverflow
Solution 13 - AndroidSevilView Answer on Stackoverflow