Android:在 X 秒后移动到不同的片段?

Android: move to a different fragment after X seconds?

我有一段用户体验流程,我想在片段 A 的文本视图中为用户显示一条消息 2 秒,然后用片段 B 替换片段 A。我通过执行以下操作来完成此操作来自片段 A.

someTextView.setText("some message");

Handler mainLooperHandler = new Handler(Looper.getMainLooper());

mainLooperHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    ((MyActivity) getActivity()).gotoTheNextFragment();
                }
            }, 2000);

而在我的activity相关方法中:

public void gotoTheNextFragment() {
    Fragment mFragmentB = new FragmentB();

    getSupportFragmentManager().beginTransaction()
            .replace(R.id.fragmentContainer, mFragmentB, "FRAGMENTB")
            .commit();
}

然而,这会导致一些问题。首先,如果用户在 postdelayed 执行时按下 'back',那么用户会在 getActivity 上得到一个空指针异常。其次,用户在尝试执行传输时有时会收到错误 "Can not perform this action after onSaveInstanceState"。

我知道如果我将 'commit' 更改为 'commitAllowingStateLoss' 那么我将避免第二个错误,但这可能不是最佳实践而且我知道在所有片段之间移动不推荐异步任务。完成此过程的更好方法是什么(显示消息,等待两秒钟,然后以不会导致崩溃的安全方式替换片段)?

无需在Activity中定义方法gotoTheNextFragment。你可以在它自己的片段中定义。

someTextView.setText("some message");

Handler mainLooperHandler = new Handler(Looper.getMainLooper());

mainLooperHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
               if(getActivity!=null){

               Fragment mFragmentB = new FragmentB();

               getActivity().getSupportFragmentManager().beginTransaction()
              .replace(R.id.fragmentContainer, mFragmentB, "FRAGMENTB")
              .commit();
            }
          }
        }, 2000);

不要每次都使用 getActivity(),因为它 returns Activity 仅创建第一次实例片段,否则它 returns 为空。因此将该实例存储在片段的 onAttach() 方法中,然后将其用于任何目的。

像这样使用它然后它应该在你向后转换时解决 nullpointerexception:

public class YourFragment extends Fragment {

private Activity _activity;

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    _activity = getActivity();
}

}

所以现在不要使用 getActivity() 而是像这样使用它,并且还对 "Can not perform this action after onSaveInstanceState" 错误使用 commitAllowingStateLoss。

Fragment mFragmentB = new FragmentB();

_activity.getSupportFragmentManager().beginTransaction()
         .replace(R.id.fragmentContainer, mFragmentB, "FRAGMENTB")
         .commitAllowingStateLoss();

我想避免使用 commitAllowingStateLoss,因为这不是好的做法,所以最后我这样做了:

定义了片段和 activity 之间的接口,并在 activity 中实现了该接口。当 activity 通过接口接收到消息时,它开始片段事务。这仍然会导致问题,因为即使 activity 执行 onPause 并且我们得到相同的 onSaveInstanceState 错误,更改片段的答案也会到达。如果 activity 处于 onPause 状态,我本可以添加一个检查,但是这样更改片段的消息就会丢失,并且用户会在原始片段而不是他想去的那个片段上恢复应用程序.

所以,最终的解决方案是定义两个布尔值。第一个布尔值是跟踪 activity 状态:

 private boolean activityIsPaused = false;

在 onPause 中设置为 true,在 onResume 中设置为 false。如果 boolean 为 false 并且通过接口返回答案,则立即执行片段事务。但是,如果布尔值设置为 true,则将另一个布尔值(例如 wantsToPerformFragmentTransaction)设置为 true。在 onResumeFragments 中(可能它在 onResume 中同样有效——我没有检查),如果布尔值 wantsToPerformFragmentTransaction 为 true,则将其设置为 false 并执行片段事务。

结果:没有错误,没有使用 commitAllowingStateLoss,结果一致,用户看到了他们应该看到的片段。