从后台弹出时不调用 Fragment 的 onResume()
Posted
技术标签:
【中文标题】从后台弹出时不调用 Fragment 的 onResume()【英文标题】:Fragment's onResume() not called when popped from backstack 【发布时间】:2013-10-24 03:02:58 【问题描述】:您好,我正在开发我正在使用的 android 应用程序,我正在使用单个 Activity
和 3 个片段。因此,考虑我有 3 个片段 AB C。当我从 A 切换到 B 时,我将 Fragment
添加到 backstack 并且对于 B 到 C 类似。现在当我从 C 中单击返回时,它显示 B 并且对于 B 到 A 类似好吧。
但问题是,当我从 C 到 B 或 B 到 A 时,它不会调用 onResume()
或 Fragment
的任何其他生命周期方法。
我想为每个Fragment
做的事情我在ActionBar
中都有不同的标题。所以,在我的代码中,当我从 A 移动到 B 或 B 到 c 时,我正在更改片段内的活动标题。但是当我点击返回时,它并没有改变。
真正的问题是什么?为什么从后台弹出后它没有为我的Fragment
调用onResume()
?我该如何解决这个问题?需要帮忙。谢谢。
【问题讨论】:
片段的onResume() 仅在活动恢复时被调用。所以这对你没有帮助。即使我现在也面临类似的问题。您可以实现OnBackStackChangedListener
并在堆栈顶部获取片段名称并根据该名称设置操作栏标题。
【参考方案1】:
Fragment
的onResume()
仅在Activity
恢复时才被调用。所以这对你没有帮助。即使我现在也面临类似的问题。你可以实现OnBackStackChangedListener
,获取栈顶的片段名称,并以此为基础设置ActionBar
标题。
private FragmentManager.OnBackStackChangedListener getListener()
FragmentManager.OnBackStackChangedListener result = new FragmentManager.OnBackStackChangedListener()
public void onBackStackChanged()
FragmentManager manager = getFragmentManager();
if (manager != null)
if(manager.getBackStackEntryCount() >= 1)
String topOnStack = manager.getBackStackEntryAt(manager.getBackStackEntryCount()-1).getName();
Log.i("TOP ON BACK STACK",topOnStack);
;
return result;
【讨论】:
我也在用这个【参考方案2】:尝试在FragmentTransaction
上使用replace
方法而不是add
。这对我有用:
FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, fragment);
ft.addToBackStack(null);
ft.commit();
【讨论】:
这行得通。可能现在应该是公认的答案。 片段 onResume() 或 onPause() 只有在调用活动 onResume() 或 onPause() 时才会被调用。它们与 Activity 紧密耦合。如果你调用 replace onStop() 将会调用。 替换fragment会重新创建UI并执行onCreateView和onViewCreated方法中写的业务逻辑。在使用这种方法之前要小心。【参考方案3】:正如其他人已经说过的那样,onResume()
仅在活动本身恢复时才被调用,所以这根本没有帮助。
您需要检查您是在添加新片段,还是在片段事务中替换现有片段:
1234563你可能已经这样做了。如果你add()
一个新的片段,之前的片段仍然存在,只是不可见。当你回到它时,由你从后堆栈中获取最后一个条目(在片段管理器中使用getBackStackEntryCount()
和getBackStackEntryAt()
),获取对应的Fragment对象(在片段管理器中使用findFragmentByTag()
) ,将该 Fragment 强制转换为您的所有 Fragment 都将从其继承的某个基类,并调用自定义方法,例如onVisible()
,在那个片段上。基类中onVisible()
的默认实现什么也不做。在每个片段中覆盖以根据需要更新工具栏标题、FAB 和其他任何内容。我还从onResume()
调用onVisible()
以避免代码重复。
【讨论】:
【参考方案4】:你可以使用这个片段方法:
@Override
public void onHiddenChanged(boolean hidden)
super.onHiddenChanged(hidden);
【讨论】:
但是当我从堆栈中弹出片段时,它不会调用它。【参考方案5】:将此代码放入您的片段中。
@Override
public void setUserVisibleHint(boolean visible)
super.setUserVisibleHint(visible);
if (visible && isResumed())
onResume();
@Override
public void onResume()
super.onResume();
if (!getUserVisibleHint())
return;
setData();
【讨论】:
【参考方案6】:我用这种方式,在你的fragment中添加这个块代码
requireActivity().supportFragmentManager.addOnBackStackChangedListener
val fm = requireActivity().supportFragmentManager
fm?.let
if (it.backStackEntryCount == YOUR_FRAGMENT_BACK_STACK_INDEX)
// your fragment visible
【讨论】:
这是最佳答案。相信我:)【参考方案7】:其他答案依赖于被命名的特定片段事务,或具有标记片段,依赖于不推荐使用的方法,或将逻辑放入活动中。这会使用其视图检测片段在后堆栈上的可见性,根据我的需要,这与onResume
足够接近。因为这与位于后堆栈的顶部有关。
用于检测屏幕上是否正在显示视图的视图扩展:(另请参阅How can you tell if a View is visible on screen in Android?)
fun View.isVisibleOnScreen(): Boolean
if (!isShown) return false
val actualPosition = Rect().also getGlobalVisibleRect(it)
val screenWidth = Resources.getSystem().displayMetrics.widthPixels
val screenHeight = Resources.getSystem().displayMetrics.heightPixels
val screen = Rect(0, 0, screenWidth, screenHeight)
return Rect.intersects(actualPosition, screen)
然后从片段中定义一个回栈监听器,观察栈顶的片段(最后添加的那个)
fun Fragment.setOnFragmentStackVisibilityListener(onVisible: () -> Unit)
val renderDelayMillis = 300L
parentFragmentManager.addOnBackStackChangedListener
Handler(Looper.getMainLooper()).postDelayed(
if (isAdded)
val topStackFragment = parentFragmentManager.fragments[parentFragmentManager.fragments.size - 1]
if (topStackFragment.view == view && isVisible && view!!.isVisibleOnScreen())
onVisible.invoke()
, renderDelayMillis)
在视图准备好之前调用返回堆栈侦听器,因此需要任意小的延迟。
【讨论】:
【参考方案8】:尝试更改 Fragment 的 onCreateView()
上的标题。
【讨论】:
但是当我从堆栈中弹出片段时,它不会调用任何生命周期方法。那我该怎么办。谢谢你的帮助。 你需要在fragment的onCreateView方法中更改标题。当您将片段弹出或添加到堆栈时,会调用 oncreateview 方法,然后根据片段类设置标题。 @HarshitRathi 我试过这个,正如@nilkash 所说,onCreateView()
在从返回堆栈中弹出片段并且新片段变得可见时不会被调用。以上是关于从后台弹出时不调用 Fragment 的 onResume()的主要内容,如果未能解决你的问题,请参考以下文章
如果从navigationController弹出时会释放ViewController?