从后台弹出时不调用 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】:

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() 在从返回堆栈中弹出片段并且新片段变得可见时不会被调用。

以上是关于从后台弹出时不调用 Fragment 的 onResume()的主要内容,如果未能解决你的问题,请参考以下文章

后台弹出js警告框 如何自动关闭

如果从navigationController弹出时会释放ViewController?

从后台打开应用程序时不调用 ViewDidAppear

从导航控制器弹出时如何保持在同一个选项卡中

显示 iOS 共享表后未调用 viewWillDisappear

Kotlin:如何从 Fragment 调用 JobIntentService?