Ошибка анимации обратного стека фрагмента Android после изменения ориентации

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

Существует LoginFragment, который является первым, что пользователь видит при входе в систему, и LockoutFragment, который может заменить LoginFragment после того, как пользователь войдет в систему, и мы увидим, что его учетная запись заблокирована (естественно).

Это типичный случай, но есть случай, когда LockoutFragment отображается первым, если, скажем, пользователь использует приложение, а его учетная запись по какой-то причине заблокирована, и мы повторно открываем активность хоста (LoginActivity), показывая LockoutFragment, но давая им кнопку «Вернуться к входу в систему», которая переключает внешний вид LoginFragment (тоже естественно).

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

private void showLockoutFragment() {
    if (mLockoutFragment == null) {
        mLockoutFragment = new LockoutFragment();
    }

    transitionToFragment(FRAGMENT_LOCKOUT, mLockoutFragment);
}

private void showLoginFragment() {
    if (mLoginFragment == null) {
        mLoginFragment = new LoginFragment();
    }

    transitionToFragment(FRAGMENT_LOGIN, mLoginFragment);
}

private void transitionToFragment(String transactionTag, Fragment fragment) {
    if (!getFragmentManager().popBackStackImmediate(transactionTag, 0)) {
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.setCustomAnimations(
                R.animator.fade_in, R.animator.fade_out,
                R.animator.fade_in, R.animator.fade_out);
        ft.addToBackStack(transactionTag);
        ft.replace(R.id.fragment_container, fragment, transactionTag);
        ft.commit();
    }
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // non configuration change launch
    if (savedInstanceState == null) {
        Bundle extras = getIntent().getExtras();
        if (extras != null) {
            // decide which fragment to show
            boolean shouldLockout = extras.getBoolean(EXTRA_SHOULD_LOCKOUT);
            if (shouldLockout) {
                showLockoutFragment();
            } else {
                showLoginFragment();
            }
        } else {
            showLoginFragment();
        }
    } else {
        // retrieve any pre-existing fragments
        mLoginFragment = (LoginFragment)getFragmentManager().findFragmentByTag(FRAGMENT_LOGIN);
        mLockoutFragment = (LockoutFragment)getFragmentManager().findFragmentByTag(FRAGMENT_LOCKOUT);
    }
}

Эти функции работают вместе как шарм, за одним исключением: когда после первоначального запуска приложения пользователь

  1. попытки войти,
  2. переносится на блокирующий фрагмент,
  3. переориентирует устройство и
  4. возвращается к фрагменту входа в систему,

фрагмент входа теперь присутствует, но невидим — как будто анимация popEnter никогда не воспроизводилась. Я знаю, что он присутствует, потому что я все еще могу взаимодействовать с ним.

Также стоит отметить следующее:

  • У меня есть setRetainInstance(true) на оба фрагмента
  • Это происходит только, когда пользователь переориентирует устройство из фрагмента блокировки.
  • Я пробовал это как на симуляторе, так и на устройстве с Lollipop с теми же результатами.

Возможно ли, что задний стек поврежден после переориентации?

Благодарю вас!


person mag725    schedule 07.05.2015    source источник


Ответы (1)


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

Контролируйте, сохраняется ли экземпляр фрагмента при повторном создании действия (например, при изменении конфигурации). Это можно использовать только с фрагментами, не находящимися в заднем стеке. [выделено мной]

Хотя это кажется мне довольно загадочным, кажется, что использование setRetainInstance(true) для фрагмента, который находится в заднем стеке, может просто иметь непредвиденные последствия. В моем случае фрагмент вроде бы сохранился, но его popEnter анимация так и не вызывалась (пост-ротация). Опять же, странно, но я думаю, просто избегайте этой комбинации.

person mag725    schedule 12.05.2015