【问题标题】:Fragment's onResume() not called when popped from backstack从后台弹出时不调用 Fragment 的 onResume()
【发布时间】: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 并在堆栈顶部获取片段名称并根据该名称设置操作栏标题。

标签: android android-fragments back-stack


【解决方案1】:

FragmentonResume() 仅在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() 在从返回堆栈中弹出片段并且新片段变得可见时不会被调用。
        猜你喜欢
        • 1970-01-01
        • 2013-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多