Подтвердить что ты не робот

Сбой сохранения состояния - цель не в менеджере фрагментов (setTargetFragment)

У меня крушение обезьяны, где

java.lang.IllegalStateException: Failure saving state: FragmentB has target not in fragment manager: FragmentA
at android.support.v4.app.FragmentManagerImpl.saveAllState(FragmentManager.java:1561)
at android.support.v4.app.FragmentActivity.onSaveInstanceState(FragmentActivity.java:475)
at com.acme.ParentActivity.onSaveInstanceState(Unknown Source)

В основном FragmentA загружает FragmentB и setTargetFragment вызывается для установки фрагмента фрагмента FragmentB.

FragmentB затем просто вызывает getTargetFragment в своем методе onCreate и зависает с целью, когда это необходимо.

Теперь я ничего не делаю в любом из вызовов onSaveInstanceState с целевым фрагментом с точки зрения установки его нулевого значения, делая любые вызовы saveFragmentInstanceState, putFragment и т.д. Вопрос в том, должен ли я что-то делать с ним?

Спасибо заранее,

Петр.

** Изменить 1 ** Я использую старую версию библиотеки поддержки и чувствую, что это может быть исправлено в последней версии, будет проверяться дальше и предоставить дополнительное обновление, если это так. Тем не менее, все еще интересно узнать, нужно ли мне что-либо делать с целевым фрагментом, который я сейчас не делаю.

** Редактировать 1 ** Исправлено с версией 8 библиотеки поддержки (не пробовали другие).

4b9b3361

Ответ 1

На самом деле вам нужно сделать две вещи, чтобы решить эту проблему:

1. Убедитесь, что вы используете getChildFragmentManager() NOT getFragmentManager() при запуске FragmentB из FragmentA

Вызов getChildFragmentManager() вернет хостинг Fragment FragmentManager, тогда как getFragmentManager() вернет хостинг Activity FragmentManager. Важно использовать getChildFragmentManager(), потому что вы размещаете фрагмент внутри другого фрагмента, поэтому родительский фрагмент должен отвечать за обработку любых транзакций с вложенным фрагментом. Если вы используете getFragmentManager(), вы столкнетесь с проблемой, с которой вы сейчас сталкиваетесь.

2. НЕ используйте setTargetFragment() и getTargetFragment(), они не будут работать при использовании getChildFragmentManager()

Вместо этого используйте getParentFragment(). Я считаю, что есть некоторая ошибка в Android прямо сейчас, где даже если вы правильно звоните

fragmentB.setTargetFragment(fragmentA, 0);

а затем отобразите FragmentB, после изменения конфигурации вызов getTargetFragment() из FragmentB вернется непосредственно вместо FragmentA.

Ответ 2

Здесь обходной путь:

поместите это в фрагмент, который вызывает проблемы:

@Override
public void onSaveInstanceState(final Bundle outState) {
    setTargetFragment(null, -1);
            ...

и не забудьте установить его в реальный целевой фрагмент, когда вам это нужно.

Ответ 3

Недавно мы столкнулись с этой проблемой. Мы внедрили собственный адаптер, расширяющий android.support.v4.app. FragmentStatePagerAdapter. С помощью android.support.v4.app. FragmentManager мы создали несколько фрагментов в пейджере, а также несколько других фрагментов вне пейджера. Осколки управляются в одном действии. Есть несколько случаев, когда мы устанавливали цель (с setTargetFragment) фрагментов без пейджинга на фрагменты, которые могут содержать или не содержать в пейджинговом адаптере. Поскольку FragmentStatePagerAdapter поддерживает только определенное количество фрагментов, фрагменты, которые были установлены как целевые, и что FragmentStatePagerAdapter, которые больше не нужны, были уничтожены... и потенциально несогласованное состояние, если фрагменты, которые имели эти цели, все еще существовали. Это привело к тому, что исключение было сброшено всякий раз, когда приложение потеряло фокус (либо когда экран выключен, либо приложение перешло в фоновый режим), т.е. При вызове onSaveInstanceState.

Чтобы предотвратить это исключение, в onSaveInstanceState мы проверили, какие фрагменты были в настоящее время в диспетчере фрагментов. Если были какие-либо несоответствия (т.е. Отсутствовал фрагмент "target" ), мы удалили фрагмент, у которого был этот целевой набор. В нашем случае у нас было только три фрагмента, где мы устанавливали цель, чтобы мы точно знали, что искать.

Я не верю, что есть какой-либо другой способ справиться с этим делом, но если у кого-то будет какая-то полезная обратная связь, это будет очень признательно.

Ответ 4

Убедитесь, что вы добавили оба фрагмента в стопку!

Я просто столкнулся с этой проблемой при добавлении нового "вызванного" фрагмента для результата поверх фрагмента "target". Первоначально я получал ту же ошибку, которая прекратилась, как только я добавил оба фрагмента в задний стек всякий раз, когда я их использовал.

Проблема возникла при поворотах экрана, поэтому ее было легко воспроизвести.

Ответ 5

Я только столкнулся с этой проблемой, и это то, что я думаю, происходит и как я ее исправил:

Экземпляр FragmentA уничтожается, а другой создается, например, при вращении устройства. Когда это произойдет, ваш FragmentB держит ссылку на FragmentA, который больше не существует.

В этом случае вы должны reset FragmentB target стать новым экземпляром FragmentA.

Я сделал это со следующим кодом в FragmentA:

@Override
    public void onAttach(Context context) {

        super.onAttach(context);

        FragmentB fragment = (FragmentB) getFragmentManager().findFragmentByTag(FragmentBtag);

        if (fragment != null) {
            fragment.setTargetFragment(this, 0);
        }


    }

Таким образом, всякий раз, когда FragmentA привязан к Контексту, то есть: происходит поворот устройства, цель FragmentB - reset, если FragmentB был создан из первых рук (если это так, то это будет на FragmentManager).

Надеюсь, это поможет.

Ответ 6

У меня была эта проблема при показе DialogFrament из другого фрагмента и использовании setTargetFragment на DialogFragment. Проблема была решена с помощью getChildFragmentManager() при отображении диалогового окна.

  • ActivityA добавил FragmentA
  • FragmentA добавил DialogFragmentB, используя ActivityA FragmentManager.
  • Вызывается dialogFragmentB.setTargetFragment(фрагмент)
  • Удален FragmentA и добавлен новый экземпляр FragmentA
  • FragmentManager, связанный с ActivityA, по-прежнему содержал DialogFragmentB, который имел первый экземпляр FragmentA в качестве целевого фрагмента.

Это вызвало вызванное исключение "Неисправность сохранения состояния - не в диспетчере фрагментов".