我有一个活动,我正在调用三个片段 - 每个片段相互依赖:
A(活动) - > f1(片段一,标题{是|应该}:列表) - > f2(片段2,标题{是|应该}:概述) - > f3(片段三,标题{是|应该}:详细信息)
ATM我使用以下方法调用来向后跳转:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount()>0){
fragmentManager.popBackStack();
}
}
}
这很好用。
我在每个片段中覆盖ActionBar标题,如下所示:
ActionBar bar = getSherlockActivity().getSupportActionBar();
bar.setTitle(R.string.title_f3);
当向前导航时(如上所示),这可以完美地工作但向后导航ActionBar的标题没有更新:
f3(标题{是|应该}:详细信息) - > f2(标题{是}:详细信息,{应该}:概述) - > f1(title {is}:detail,{should}:list)
显然,我可以在显示片段时再次更新它。但我的调试器永远不会停留在任何方法中,除了它将被称为 onResume()。
在 popBackStack()之后,实际上是否在前一个片段中调用了任何方法?
答案 0 :(得分:16)
我知道答案有点迟,但对于在这里航行的人来说,这可能会有所帮助!
首先是第一件事:popBackStack()没有弹出片段,它会弹出片段事务。因此,最后一个片段事务在被调用时会被反转。如果您当前正在显示FragmentA并且您的交易是:
m1 <- structure(c(1L, 0L, 1L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 1L, 0L, 1L,
0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L,
0L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, 0L,
1L, 0L, 0L, 1L, 0L), .Dim = c(5L, 10L))
它将用FragmentB替换FragmentA,并将该事务(不是片段)添加到后端堆栈。如果你然后按下后退按钮,它会从后面的堆栈中弹出事务,这就是“用FragmentB替换这个FragmentA”。本质上,该指令反转最后一个事务并将其从执行的事务堆栈中删除。如果原始FragmentA仍然存在,则使用该片段。如果它被摧毁了,它会成为一个新的。
因此,如果Fragment尚未被破坏,那么在使用popBackStack()之后调用该片段,就会调用onStart()和onResume()方法。如果先前已经破坏了Fragment,那么将从onAttach()开始调用生命周期方法。这与按活动上的后退按钮相同。
现在重要一点,当我们弹回堆栈时会发生什么重新碎片生命周期?就像片段交易之前所说的那样:
场景1:您的fragmentB在事务之前尚未存在。 在这种情况下,onCreate()和onAttach()方法在事务期间被调用,因此如果你调用popBackStack()并反转事务,片段将被销毁和分离(注意FragmentA可能已经存在,所以替换它不会像我们一样破坏它不要撤消片段创建)。在这种情况下,将从onAttach()开始调用生命周期方法。
场景2:您的fragmentB在事务之前已经存在。在这种情况下,片段不会被销毁,下次访问时会调用onStart()和onResume()方法。
这位老师在这里解释了一些关于使用popbackstack()http://vinsol.com/blog/2014/09/19/transaction-backstack-and-its-management/和片段生命周期http://vinsol.com/blog/2014/10/22/fragment-view-state-retention-a-dirty-solution/的事情。其他相关帖子也值得一读!
答案 1 :(得分:4)
在BaseActivity中使用addOnBackStackChangedListener方法,任何时候都会在后台堆栈更改时调用
getSupportFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
FragmentManager fm = getSupportFragmentManager();
if (fm != null) {
int backStackCount = fm.getBackStackEntryCount();
if (backStackCount == 0) {
if (getSupportActionBar() != null) {
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
}
setToolbarTittle(R.string.app_name);
} else {
if (getSupportActionBar() != null) {
getSupportActionBar().setHomeAsUpIndicator(R.drawable.back);
}
}
}
}
});
答案 2 :(得分:2)
我的解决方法是在将片段设置为新标题之前获取片段中操作栏的当前标题。这样,一旦弹出片段,我就可以改回那个标题。
@Override
public void onResume() {
super.onResume();
// Get/Backup current title
mTitle = ((ActionBarActivity) getActivity()).getSupportActionBar()
.getTitle();
// Set new title
((ActionBarActivity) getActivity()).getSupportActionBar()
.setTitle(R.string.this_fragment_title);
}
@Override
public void onDestroy() {
// Set title back
((ActionBarActivity) getActivity()).getSupportActionBar()
.setTitle(mTitle);
super.onDestroy();
}
答案 3 :(得分:1)
您还可以阅读另一本好书source。
我认为,重点是您在片段B上执行的事务的区别。如果是 add ,则如果片段A 没有调用任何生命周期方法,它是替换,您将获得关于这些方法的一些调用。
答案 4 :(得分:-1)
我使用以下解决方法:
1)在将第二个片段添加到第一个片段之前设置第一个片段setHasOptionsMenu(false)
。
2)从第二个片段返回后,在setHasOptionsMenu(true)
中设置第一个片段onOptionsItemSelected()
。
3)应该调用第一个片段的onCreateOptionsMenu()
,你可以在这里更改操作栏。
但我想知道一个更好的解决方案。
答案 5 :(得分:-3)
您可以在android docs here中找到一个不错的Fragment
生命周期图表。所以,是的,如果片段从后台onCreateView()
移到前台,onActivityCreated()
,onStart()
和onResume()
被调用。