正确/最佳方式处理Android片段交易问题

pdp*_*ech 4 java android fragment android-fragments

在我的开源Android应用程序中,发现了一个问题,即特定片段会出现在另一个片段之上,或者在特定情况下会使应用程序崩溃。

如果您想查看更多信息和示例屏幕截图,请查看GitHub上的问题:https : //github.com/rpi-mobile/RPIMobile-Android/issues/31

我已查明原因,但想知道使用android.support.v4.app包中的哪些方法来解决问题。

在中MainActivity.java,是用于FragmentTransaction.replace()切换片段的导航抽屉的代码。

之所以出现此问题,是因为在中MapFragment,我使用了:

ViewMapFragment vmf = new ViewMapFragment();
FragmentTransaction ft = getSherlockActivity().getSupportFragmentManager().beginTransaction();
ft.addToBackStack(null);
ft.replace(R.id.content_frame, vmf);
ft.commit();
Run Code Online (Sandbox Code Playgroud)

而在ViewMapFragmentonDestroyView()

FragmentManager fm = getSherlockActivity().getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.remove(fm.findFragmentById(R.id.mapview));
ft.commit();
Run Code Online (Sandbox Code Playgroud)

onDestroyView()正确删除ViewMapFragment从视图,但如果你有它的视图,并使用导航抽屉变化到不同的片段,MapFragment还是回堆栈。

因此,对于我的问题:

1)在尝试删除/替换碎片之前,如何检查特定碎片是否在后堆栈上;如果您什么都不做,则应用程序不会崩溃(即不检查)吗?例如popBackStack(),在后栈上没有任何东西时调用。

2)应该使用FragmentManager类方法尝试MapFragment从后堆栈中删除还是应该使用FragmentTransaction方法?优点与缺点?

3)popBackStack()和之间的UI有什么区别popBackStackImmediate()?用户是否看到一些故障过渡?

Ayz*_*zen 5

根据FragmentTransaction的文档,当您调用addToBackStack方法时,它仅记住您在该事务中执行的操作。调用popBackStack方法时,它将撤消那些操作并执行它们。

所以,会发生什么:

  1. 当我们从MapFragment转到ViewMapFragment时,FragmentManager记得删除MapFragment和添加ViewMapFragment操作。
  2. 然后,我们使用导航抽屉转到任何其他片段,这将导致ViewMapFragment删除操作,然后添加从抽屉中选择的片段。
  3. 最后,当我们按“返回”按钮时,将调用popBackStackImmediate,并且FragmentManager执行相反的操作:删除了ViewMapFragment(实际上已经删除了)并添加了MapFragment。这就是发生的问题-所选片段仍然存在,因此我们同时在屏幕上有两个片段。

有几种方法可以处理这种情况:

  1. 只需将导航抽屉操作添加到堆栈即可。
  2. 每次由导航抽屉启动片段切换时,请清除回栈。

要清除后退堆栈,您可以使用以下代码(相关问题):

getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Run Code Online (Sandbox Code Playgroud)

如果将此行放在selectItem方法的开头,该错误将得到修复。

还有你的问题:

  1. 您可以使用FragmentManager.findFragmentByTag方法检查片段是否在后堆栈中。请参阅答案末尾的示例。
  2. 从技术上讲,后向堆栈条目可以包含多个片段,但我认为没有办法从中删除单个片段。除了删除堆栈,您还可以清除堆栈(请参阅此问题)。
  3. 主要区别在于popBackStack会在实际开始弹出过程之前为您提供执行操作的机会(它将在应用程序返回其事件循环时启动)。

例。例如,我们添加了一个带有标签“ fragment-1”的片段:

getSupportFragmentManager()
        .beginTransaction()
        .replace(R.id.frame, new TestFragment(), "fragment-1")
        .commit();
Run Code Online (Sandbox Code Playgroud)

然后,我们将其放回堆栈中,并用另一个片段替换它:

getSupportFragmentManager()
        .beginTransaction()
        .addToBackStack(null)
        .replace(R.id.frame, new TestFragment(), "another-fragment")
        .commit();
Run Code Online (Sandbox Code Playgroud)

此时,getSupportFragmentManager()。findFragmentByTag(“ fragment-1”)返回我们的第一个片段(它是从后堆栈条目中获取的)。现在,我们可以检查该片段是否通过iFyre方法添加到其活动中-如果它返回false,则可以假设该片段位于后向堆栈中。