Android 方向改变后片段回退动画失败

Android fragment backstack animation fail after orientation change

我有一个 activity,它包含两个片段,一次只显示一个片段。实际上,通过不同的环境条件,用户应该能够在任何给定时间在两者之间切换。

有一个 LoginFragment,这是用户在登录时首先看到的东西,还有一个 LockoutFragment,它可能会在用户登录后取代 LoginFragment,我们会看到他们的帐户被锁定(自然)。

这是典型的情况,但是有一种情况是先出现LockoutFragment,如果说用户正在使用该应用程序并且他们的帐户由于某种原因被锁定,我们重新打开主持人 activity (LoginActivity),显示 LockoutFragment,但给他们一个 "Return to login" 按钮,它切换 LoginFragment 的外观(也是自然的)。

因此,我的目标是允许用户在两​​个片段之间切换,以先显示的为准。我的主机activity使用了以下函数来实现这个效果:

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。根据该方法的文档:

Control whether a fragment instance is retained across Activity re-creation (such as from a configuration change). This can only be used with fragments not in the back stack. [emphasis mine]

虽然这对我来说显得相当神秘,但似乎在返回堆栈上的片段上使用 setRetainInstance(true) 可能只会产生意想不到的后果。在我的例子中,该片段似乎被保留,但它的 popEnter 动画从未被调用(post-旋转)。再次,很奇怪,但我想只是避免这种组合。