方向更改后,Android片段反向堆栈动画失败

时间:2022-11-05 19:50:28

I have an activity which hosts two fragments with only one shown at a time. Effectively the user, through different environmental conditions, should be able to toggle between the two at any given time.

我有一个活动,它主持两个片段,一次只显示一个片段。有效地,用户可以通过不同的环境条件在任何给定时间在两者之间切换。

There is a LoginFragment which is the first thing the user sees on login, and a LockoutFragment which may replace the LoginFragment after a user logs in and we see their account is locked (naturally).

有一个LoginFragment是用户登录时看到的第一件事,还有一个LockoutFragment可以在用户登录后替换LoginFragment,我们看到他们的帐户被锁定(自然)。

That is the typical case, but there is a case in which LockoutFragment is presented first, if say, the user is using the app and their account is locked for some reason, and we re-open the host activity (LoginActivity), showing the LockoutFragment, but giving them a button to "Return to login", which toggles appearance of the LoginFragment (also naturally).

这是典型的情况,但有一种情况是首先显示LockoutFragment,如果用户正在使用该应用程序并且他们的帐户由于某种原因被锁定,我们重新打开主机活动(LoginActivity),显示LockoutFragment,但给他们一个“返回登录”按钮,切换LoginFragment的外观(也很自然)。

Thus, my goal is to allow a user to toggle between the two fragments, whichever is displayed first. My host activity uses the following functions to achieve this effect:

因此,我的目标是允许用户在两​​个片段之间切换,无论哪个先显示。我的主机活动使用以下函数来实现此效果:

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);
    }
}

These functions work together like a charm, with one exception: when, after initial launch of the app, a user

这些功能像魅力一样工作,但有一个例外:在应用程序首次启动后,用户

  1. attempts log in,
  2. 尝试登录,

  3. is taken to the lockout fragment,
  4. 被带到了锁定片段,

  5. reorients the device, and
  6. 重新定位设备,和

  7. navigates back to the login fragment,
  8. 导航回登录片段,

the login fragment is now present but invisible - as if the popEnter animation was never played. I know it is present because I can still interact with it.

登录片段现在存在但不可见 - 就好像从未播放过popEnter动画一样。我知道它存在,因为我仍然可以与它互动。

It is also worth noting the following:

值得注意的还有以下几点:

  • I have setRetainInstance(true) on both fragments
  • 我对两个片段都有setRetainInstance(true)

  • This only occurs when a user reorients the device from the lockout fragment
  • 仅当用户从锁定片段重新定向设备时才会发生这种情况

  • I have tried this on both a simulator and device running Lollipop with same results
  • 我已经在模拟器和运行Lollipop的设备上尝试了相同的结果

Is it possible that the back stack is being corrupted after reorientation?

重新定位后后堆栈是否可能被损坏?

Thank you!

1 个解决方案

#1


0  

Ok, so it turns out the issue actually lies in my use of setRetainInstance. According to the docs for that method:

好的,事实证明问题实际上在于我使用了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]

控制是否在活动重新创建(例如从配置更改)中保留片段实例。这只能用于不在后栈中的片段。 [强调我的]

While this appears rather cryptic to me, it seems that using setRetainInstance(true) on a fragment that is on the back stack could simply have unintended consequences. In my case, the fragment seemed to be retained, but its popEnter animation was never being called (post-rotation). Again, weird, but I guess just avoid that combination.

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

#1


0  

Ok, so it turns out the issue actually lies in my use of setRetainInstance. According to the docs for that method:

好的,事实证明问题实际上在于我使用了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]

控制是否在活动重新创建(例如从配置更改)中保留片段实例。这只能用于不在后栈中的片段。 [强调我的]

While this appears rather cryptic to me, it seems that using setRetainInstance(true) on a fragment that is on the back stack could simply have unintended consequences. In my case, the fragment seemed to be retained, but its popEnter animation was never being called (post-rotation). Again, weird, but I guess just avoid that combination.

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