Удалить все дочерние фрагменты

У меня есть фрагмент, который xml содержит что-то вроде этого:

<RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="230dp">

        <fragment
            android:id="@+id/myFragmen1"
            android:name="com...widgets.myViewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/text""/>

    </RelativeLayout>

Мне нужно добавить 4 разных фрагмента в мой XML. Родительский фрагмент я начинаю так:

getFragmentManager().beginTransaction()
            .replace(R.id.frameContainer, myFragment1)
            .addToBackStack(null)
            .commit();

Итак, все работает нормально, пока я не пытаюсь показать фрагмент более 1 раза. Если я щелкаю назад и пытаюсь открыть фрагмент снова, я получаю эти ошибки:

 Caused by: java.lang.IllegalArgumentException: Binary XML file line #17: Duplicate id 0x7f080130, tag null, or parent id 0xffffffff with another fragment for com...widgets.myViewPager

Я знаю проблему и у меня есть решение. Я мог бы удалить фрагмент в onDestroy. Но я не хочу этого делать! XML, который содержит другой фрагмент, является динамическим. Я получаю макет через пакет, поэтому в этом фрагменте я не могу знать, какой фрагмент показан. И если я использую эту часть более 1 раза, я должен быть уверен, что имя одно и то же. Итак, мой вопрос: есть ли возможность удалить в каждом фрагменте? Чтоб каждый фрагмент удалял сам себя, а родителю нечего делать?

Спасибо за помощь

РЕДАКТИРОВАТЬ:

    MyFragment myFragment1 = new MyFragment();

    Bundle bundle = new Bundle();
    bundle.putInt("layout",R.layout.my_fragment);
    myFragment1.setArguments(bundle);

    getFragmentManager().beginTransaction()
            .replace(R.id.frameContainer, myFragment1)
            .addToBackStack(null)
            .commit();

Эти звонки я делаю из разных мест. Для каждого звонка я могу сделать свой собственный xml с разными фрагментами. И в моем родительском фрагменте я делаю это:

    int layoutId = this.getArguments().getInt("layout", 0);
    if(layoutId==0)
        throw new RuntimeException("LayoutId not found");

    return inflater.inflate(layoutId,container,false);

После этого мой фрагмент загружает xml со всеми фрагментами, которые я установил в xml. Так что я могу определить вид снаружи. После уничтожения этого фрагмента и повторного открытия он выдаст ошибку. Это потому, что все фрагменты в моем xml не уничтожены! Мой родительский фрагмент не знает, какие фрагменты находятся в xml, поэтому я хочу, чтобы они уничтожили себя в своем классе.

1 ответ

Эта ошибка происходит потому, что ребенок Fragments могут быть созданы и отображены только программно. XML-макет Fragment не может содержать <fragment ... /> тег. Из документов:

You cannot inflate a layout into a fragment when that layout includes a <fragment>. Nested fragments are only supported when added to a fragment dynamically.

Вот что вам нужно сделать:

ШАГ 1: Изменить родительский FragmentXML-макет выглядит следующим образом:

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="230dp">

    <!-- <fragment
        android:id="@+id/myFragmen1"
        android:name="com...widgets.myViewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" /> -->

    <FrameLayout
        android:id="@+android:id/childfragmentregion"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="0dp"
        android:layout_weight="1" >
    </FrameLayout>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/text""/>

</RelativeLayout>

ШАГ 2: Затем для замены новых дочерних фрагментов:

FragmentManager fm = getChildFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.childfragmentregion, new SomeXYZFragment(), "some_xyz_fragment");
ft.commit();

ШАГ 3: переопределить вашего родителя Fragment"s onDetach() метод следующим образом:

@Override
public void onDetach() {
    super.onDetach();

    try {
        Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
        childFragmentManager.setAccessible(true);
        childFragmentManager.set(this, null);

    } catch (NoSuchFieldException e) {
        throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    }
}

Это будет работать без исключений. Я прошу вас уточнить вторую часть вашего вопроса: мне не ясно, какие Fragment получает данные в Bundle, Я могу помочь вам в дальнейшем, если вы сделаете это более ясным.

Другие вопросы по тегам