Не удается сохранить вложенные фрагменты

Есть ли другой способ сохранения состояния вложенного фрагмента? Или, если мы не должны этого делать, почему? Спасибо!

02-13 11:42:43.258: E/AndroidRuntime(7167): java.lang.IllegalStateException: Can't retain fragements that are nested in other fragments
02-13 11:42:43.258: E/AndroidRuntime(7167):     at android.support.v4.app.Fragment.setRetainInstance(Fragment.java:742)

Ответ 1

Вы можете использовать FragmentManager.saveFragmentInstanceState(Fragment) для извлечения состояния фрагмента. Возвращаемое значение реализует Parcelable, поэтому вы можете поместить его в Bundle.

Для восстановления вы можете предоставить состояние после создания фрагмента с помощью Fragment.setInitialSavedState(Fragment.SavedState).

Ответ 2

Поскольку библиотека поддержки 20+ (https://code.google.com/p/android/issues/detail?id=74222), есть ошибка с возможностью восстановления экземпляров для дочерних фрагментов, есть исправление для нее - http://ideaventure.blogspot.com.au/2014/10/nested-retained-fragment-lost-state.html

Код с веб-страницы (добавьте это в свой родительский фрагмент) -

private FragmentManager childFragmentManager() {//!!!Use this instead of getFragmentManager, support library from 20+, has a bug that doesn't retain instance of nested fragments!!!!
        if(mRetainedChildFragmentManager == null) {
            mRetainedChildFragmentManager = getChildFragmentManager();
        }
        return mRetainedChildFragmentManager;
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        if (mRetainedChildFragmentManager != null) {
            //restore the last retained child fragment manager to the new
            //created fragment
            try {
                Field childFMField = Fragment.class.getDeclaredField("mChildFragmentManager");
                childFMField.setAccessible(true);
                childFMField.set(this, mRetainedChildFragmentManager);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);

    }

Ответ 3

Проблема: mChildFrgamentManager воссоздается (https://code.google.com/p/android/issues/detail?id=74222)
Обход проблемы: Сохранение mChildFrgamentManager, если фрагмент имеет setRetainInstance(true):

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    if (getRetainInstance()) {
        if (mRetainedChildFragmentManager != null) {
            try {
                Field childFMField = Fragment.class.getDeclaredField("mChildFragmentManager");
                childFMField.setAccessible(true);
                childFMField.set(this, mRetainedChildFragmentManager);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } else {
            mRetainedChildFragmentManager = getChildFragmentManager();
        }
    }
}

Предупреждение: С этим кодом setRetainInstace следует вызывать перед onAttach.

P.S: Это немного улучшенная версия ответа @attels.

Ответ 4

Это больше не ограничение с последней библиотекой поддержки, после AOSP commit.

Ниже сообщение о фиксации:

Разрешить setRetainInstance (true) на вложенных фрагментах

Сохранение произвольно вложенных фрагментов в конфигурационных изменениях как объекты неконфигурации. Это позволяет использовать save-instance дочерние фрагменты как произвольные непрозрачные зависимости в других фрагменты.