正在阅读文档 http://developer.android.com/reference/android/support/v4/app/FragmentManager.html,有一种方法可以根据事务名称或提交提供的 id 弹出返回堆栈。使用名称may更容易,因为它不需要跟踪可能更改的数字并强化“唯一的返回堆栈条目”逻辑。
因为您只需要一个返回堆栈条目Fragment
,将后台状态名称命名为 Fragment 的类名称(通过getClass().getName()
)。那么当更换一个Fragment
, 使用popBackStackImmediate() http://developer.android.com/reference/android/support/v4/app/FragmentManager.html#popBackStackImmediate%28java.lang.String,%20int%29方法。如果返回true,则说明后台栈中有该Fragment的实例。如果没有,则实际执行Fragment替换逻辑。
private void replaceFragment (Fragment fragment){
String backStateName = fragment.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0);
if (!fragmentPopped){ //fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(backStateName);
ft.commit();
}
}
EDIT
问题是 - 当我启动 A 然后启动 B,然后按后退按钮 B
被移除并恢复A。再次按后退按钮应该
退出应用程序。但它显示一个空白窗口,需要再按一次
关闭它。
这是因为FragmentTransaction
被添加到返回堆栈中,以确保我们稍后可以将片段弹出到顶部。对此的快速解决方案是压倒性的onBackPressed()
如果返回堆栈仅包含 1,则结束 ActivityFragment
@Override
public void onBackPressed(){
if (getSupportFragmentManager().getBackStackEntryCount() == 1){
finish();
}
else {
super.onBackPressed();
}
}
关于重复的返回堆栈条目,如果片段尚未弹出,则替换片段的条件语句显然是不同的比我原来的代码片段的。您所做的就是添加到返回堆栈,无论返回堆栈是否被弹出。
像这样的东西应该更接近你想要的:
private void replaceFragment (Fragment fragment){
String backStateName = fragment.getClass().getName();
String fragmentTag = backStateName;
FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0);
if (!fragmentPopped && manager.findFragmentByTag(fragmentTag) == null){ //fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content_frame, fragment, fragmentTag);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(backStateName);
ft.commit();
}
}
条件发生了一些变化,因为在可见时选择相同的片段也会导致重复的条目。
执行:
我强烈建议不要采用更新的replaceFragment()
方法分开,就像您在代码中所做的那样。所有逻辑都包含在该方法中,移动部件可能会导致问题。
这意味着您应该复制更新的replaceFragment()
方法进入你的类然后改变
backStateName = fragmentName.getClass().getName();
fragmentPopped = manager.popBackStackImmediate(backStateName, 0);
if (!fragmentPopped) {
ft.replace(R.id.content_frame, fragmentName);
}
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(backStateName);
ft.commit();
所以这很简单
replaceFragment (fragmentName);
EDIT #2
要在返回堆栈更改时更新抽屉,请创建一个接受 Fragment 并比较类名的方法。如果有任何匹配,请更改标题和选择。还添加一个OnBackStackChangedListener
如果有有效的片段,让它调用您的更新方法。
例如,在活动的onCreate()
, add
getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
Fragment f = getSupportFragmentManager().findFragmentById(R.id.content_frame);
if (f != null){
updateTitleAndDrawer (f);
}
}
});
还有另一种方法:
private void updateTitleAndDrawer (Fragment fragment){
String fragClassName = fragment.getClass().getName();
if (fragClassName.equals(A.class.getName())){
setTitle ("A");
//set selected item position, etc
}
else if (fragClassName.equals(B.class.getName())){
setTitle ("B");
//set selected item position, etc
}
else if (fragClassName.equals(C.class.getName())){
setTitle ("C");
//set selected item position, etc
}
}
现在,每当返回堆栈发生变化时,标题和选中的位置将反映可见的Fragment
.