所以,有一些类似的问题,但我没有找到解决这个问题的单一问题。 official android documentation似乎很直观,但是当我实现一个工作流程更复杂的应用程序时,碎片堆栈会变得混乱,并且会发生奇怪的事情。我为简单的应用程序开发了一个框架,其中包含单个活动的概念,可以通过其片段访问它以启动其他片段。我就这样做了:
1-我让我的主要活动实现一个名为" FragmentDelegate"
的界面public interface FragmentDelegate {
public void startFragment(CCFragment fragment, boolean addToBackStack);
}
2- startFrargment方法的实现:
@Override
public void startFragment(CCFragment fragment, boolean addToBackStack) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragment.setFragmentDelegate(this);
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.slide_in_right,
R.anim.slide_out_left, R.anim.slide_in_left,
R.anim.slide_out_right);
fragmentTransaction.replace(CONTENT_VIEW_ID, fragment,
"callerFragmentClassName");
if (addToBackStack)
fragmentTransaction.addToBackStack("callerFragmentClassName");
fragmentTransaction.commitAllowingStateLoss();
}
关于这一点很酷的是,我可以从任何片段调用:
mFragmentDelegate.startFragment(aNewFragment, addToBackStack);
现在可以考虑以下情况:
我用一个初始片段开始我的活动,让我们说片段A. 从片段A,我调用Camera Activity获取结果。当结果到来时,我启动片段B(向后台添加A)。从B开始,片段C 没有将B添加到Backstack。所以我们在后台堆中有这个:
[A] [C]
如果我按下后退按钮,我会回到A. 如果我重复这个过程,背板就会搞砸了,当我按下它时,它会一次又一次地把我带到C片段......
我知道这很难理解(我更难解释,因为英语不是我的母语)但是如果有人可以向我解释一下android片段的堆栈真的是如何工作的,或者为应用提供某种骨架,会很棒。
答案 0 :(得分:18)
<强>解释强>
当FragmentManager恢复保存的FragmentTransactions(例如用户单击Back按钮或者你在其上调用了一些pop方法)时,它会执行与保存的FragmentTransaction中存储的操作相反的操作。您可以看到确切的代码here,这非常简单。
在您的情况下,保存的操作类型为“replace”,因此还原意味着删除所有添加的Fragment实例并重新添加删除的实例。所以当你有这样的片段堆栈时:
[A] [B]
FragmentManager知道,必须删除[B] Fragment实例并在弹出操作时添加[A]。问题是,您用[C]替换了[B]:
[A] [C]
不幸的是,保存的Fragment BackStack条目不知道[C]。因此在弹出操作期间,FragmentManager将重新添加[A],不会找到[B]因此它不会对此做任何事情,并将[C]保留在原来的位置。
<强>解决方案强>
此问题的一种可能解决方案是使用子片段。片段-A是顶级片段,但片段-B和片段-C是WrapperFragment的子片段。
基本上,当您导航到Fragment-B时,在已保存的事务中将Fragment-A替换为WrapperFragment:
[A] [[B]]
之后,当用户导航到Fragment-C时,只能用[C]替换WrapperFragment的[B]:
[A] [[C]]
当用户按下Back按钮时,我们将正确返回Fragment-A:
[A]
<强>演示强>
我已经组装了一个GitHub project来演示这种技术。
答案 1 :(得分:1)
我无法弄清楚你是如何一次又一次地弹出C片段的,而不是你所做的全部图片,但是这里你背后的错误是什么:
BackStack
条目实际上保存了整个当前状态
FragmentManager
,而不仅仅是单个片段。即如果你表演
单个事务中具有多个片段的多个操作
调用addToBackStack()
,你将保存所有片段的状态
即将到来的交易。
当您致电addToBackStack()
时,实际上是在添加下一个
说实话,如果你打电话,就说到后桅
addToBackStack()
当你添加A片段时,你实际上有一个状态
B和A背后的国家 - [A] [B],而不是[A] [C]。
我建议您使用此代码
并使用调试器查看状态来尝试所有内容
FragmentManager
对象:
int count = fragmentManager.getBackStackEntryCount();
fragmentTransaction.addToBackStack(String.valueOf(count));
通过这种方式,您可以跟踪应用中的实际情况。
答案 2 :(得分:0)
首先要记住:
.replace() = .remove().add()
一些可能的解决方案
public void onBackPressed(){
// here you have to remove your last fragment.
super.onBackPressed();
}
/////////////////////////////////////////////// ////////////////////////////////////////////////
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
this.finish();
return false;
} else {
getSupportFragmentManager().popBackStack();
removeCurrentFragment();
return false;
}
}
return super.onKeyDown(keyCode, event);
}
public void removeCurrentFragment() {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Fragment currentFrag = getSupportFragmentManager().findFragmentById(R.id.detailFragment);
if (currentFrag != null)
transaction.remove(currentFrag);
transaction.commit();
}
/////////////////////////////////////////////// /////////////////////////////////////////
有关碎片堆叠的更多信息 Check Here和Here
答案 3 :(得分:0)
这似乎不是一个解决方案,但我认为如果你不在这样的情况下使用片段会更好。最初只有一个Activity并且根据需要替换片段似乎是一个好主意但是当你尝试以这种方式构建你的应用程序时,事情会变得混乱。 (我去过那里,我从经验中说话)。 自己管理BackStack只是其中一个问题。当你走得更远的时候,你最终会遇到一个活动,里面有很多相关的代码,这根本就不酷!
我建议你为你已经获得的每个片段创建一个活动,然后简单地将你的片段放入其中。在某些情况下,您的活动仍然可以有多个片段(比如平板电脑或横向模式),在其他情况下(如肖像模式)也可以有一个片段但是您不必再使用替换方法了。
活动可以有父活动,因此BackStack问题将以尽可能多的方式解决。 这只是基于我对片段的经验的建议。做你认为最好的事情。