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

У меня есть фрагмент, в котором 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, поэтому я хочу, чтобы они уничтожали себя в своем классе.


person user3621165    schedule 23.06.2014    source источник
comment
до чего ты дошел с этим?   -  person Y.S    schedule 08.01.2017


Ответы (1)


Эта ошибка возникает из-за того, что дочерние элементы Fragment могут быть созданы и отображены только программно. 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. Измените XML-макет родительского Fragment следующим образом:

<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. Переопределите метод onDetach() вашего родителя Fragment следующим образом:

@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. Я могу помочь вам дальше, если вы сделаете это более ясным.

person Y.S    schedule 23.06.2014
comment
Спасибо за помощь, но думаю, это не поможет. Может быть, мне следует объяснить это немного лучше: у меня есть 4 фрагмента, которые содержат простое содержимое, например 2 просмотра текста,... Следующий комментарий слишком длинный для одного комментария :) - person user3621165; 23.06.2014
comment
Теперь мне просто нужно сделать xml, который содержит только те фрагменты, которые мне нужны. Я делаю это так, потому что у меня есть несколько разных мест, откуда я покажу фрагмент, но имеют другое содержание. Поэтому я просто создаю xml с фрагментами и помещаю эти xml в пакет. При запуске фрагмент загружает xml с разными фрагментами. Таким образом, я могу обрабатывать содержимое представления извне, но мне не нужно заботиться о данных, которые должны отображаться. - person user3621165; 23.06.2014
comment
Я лишь указал на причину ошибки, которую считаю правильной. И я не совсем понимаю, что вы имеете в виду, когда говорите, что хотите поместить xml в пакет. Я так понимаю, вы имеете в виду, что вы передаете строку value TextViews в дочерних Fragments в Bundles. - person Y.S; 23.06.2014
comment
Для каждого места, откуда я хочу вызвать фрагмент, я создаю xml, который содержит мои фрагменты (как xml в моем вопросе). Затем я помещаю layoutId xml в пакет и затем раздуваю эти xml. Я редактирую свой вопрос, надеюсь, это поможет вам понять - person user3621165; 23.06.2014