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

#android #android-fragments #fragmentmanager

#Android #android-фрагменты #fragmentmanager

Вопрос:

У меня есть фрагмент, 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. чего вы достигли с этим?

Ответ №1:

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

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

Комментарии:

1. Спасибо за помощь, но я думаю, это не поможет. Может быть, мне следует объяснить это немного лучше: у меня есть 4 фрагмента, которые содержат только простой контент, например, 2 Textviews… Следующий комментарий слишком длинный для одного комментария 🙂

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

3. Я просто указал причину ошибки, которую я считаю правильной. И я не совсем понимаю, что вы подразумеваете под «помещением xml в пакет». Я так понимаю, вы имеете в виду, что вы передаете строковое значение TextView s в дочернем Fragment s в Bundle s.

4. Для каждого места, откуда я хочу вызвать фрагмент, я создаю xml, который содержит мои фрагменты (например, xml в моем вопросе). Затем я помещаю layoutId xml в пакет и затем раздуваю эти xml. Я редактирую свой вопрос, надеюсь, это поможет вам понять