【问题标题】:Remove specefic fragment from backstack that is not on top of backstack从 backstack 中删除不在 backstack 顶部的特定片段
【发布时间】:2020-01-18 11:02:10
【问题描述】:

短版:

我通过replace方法(A -> B -> C -> D -> E)将5个片段全部添加到容器中,现在我想从我的backStack(C)中删除3rdfragment并留在当前页面,怎么做?

问题:

我有 3 个片段,FragmentAFragmentBFragmentC,用户从 A to B then C 导航。 在 FragmentC 中,当用户执行操作时(我称之为 ActionX)我需要从我的片段管理器 BackStack 中删除 FragmentB(而用户仍在 FragmentC 中)并且我不希望用户注意到任何事情,就在他在手机上按下不同的片段显示(所以如果用户按下片段A显示时发生ActionX,如果不是片段B显示)

这就是我显示我的fragments 的方式(我为名称和标签设置片段名称,以便在需要时找到它们)

public void showFragment(Fragment fragment) {
        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
        String tag = fragment.getClass().getSimpleName();
        fragmentTransaction.replace(R.id.fragment_container, fragment, tag);
        fragmentTransaction.addToBackStack(tag);
        fragmentTransaction.commit();
}

我尝试了一些 SO 线程中提到的解决方案(例如 this),但它们仅适用于堆栈中的顶部片段,或者他们建议不使用 FragmentB(我不能这样做,因为我不知道用户会做什么),还发现并且从堆栈中删除 FragmentB 不起作用。 一种解决方案是覆盖我的 Activity 的 onBackPressed 并检查 ActionX 是否发生并弹出我的 backStack 两次。

我尝试了什么:

  1. 这不起作用(fragmentBInStack 不为​​空,但当我删除它时没有任何反应)
val fragmentBInStack = manager.findFragmentByTag(FragmentB::class.java.simpleName)
fragmentBInStack?.let {
    manager.beginTransaction().remove(it).commit()
}
  1. 如果我使用POP_BACK_STACK_INCLUSIVE 的用户0 instad,此代码将同时删除FragmentC 和FragmentB 并显示FragmentA(我想留在FragmentC),它只会弹出FragmentC 并显示FragmentB
manager.popBackStack(FragmentB::class.java.simpleName, FragmentManager.POP_BACK_STACK_INCLUSIVE)

这是我想做的一些示例代码

class FragmentC : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.findViewById<View>(R.id.action_x).setOnClickListener {

            //here I want to remove FragmentB from back Stack and stay in FragmentC, just later when user presses back I want to show FragmentA
            val manager = activity!!.supportFragmentManager
            val fragmentBInStack = manager.findFragmentByTag(FragmentB::class.java.simpleName)
            fragmentBInStack?.let {
                manager.beginTransaction().remove(it).commit()
            }
        }
    }

【问题讨论】:

    标签: java android android-fragments kotlin fragment-backstack


    【解决方案1】:

    好的,首先,您必须在单独的事务中添加您的片段,并将replace更改为add

    supportFragmentManager
        .beginTransaction()
        .add(R.id.fragment_container, fragment2, tag2)
        .addToBackStack(tag2)
        .commit()
    

    然后像你一样删除片段:

    val fragment2 = supportFragmentManager.findFragmentByTag(tag2)!!
    supportFragmentManager.beginTransaction().remove(fragment2).commit()
    

    最后一步就是弹出BackStack:

    supportFragmentManager.popBackStack()
    

    【讨论】:

    • 感谢您的回答,但是我在使用 add 时总是遇到问题,所以我更喜欢使用 replace,如果我使用 add(),您的代码效果很好。当我使用 replace() 时,你对删除片段有什么建议吗?
    • 当我使用这段代码(使用add)返回FragmentA时,我必须按两次返回按钮才能返回上一个片段(试试看)
    • 您可以避免按两次返回按钮添加第一个片段而不将其添加到返回堆栈
    • 我理解,但是 replace 方法本质上与为所有当前添加的片段调用 remove(Fragment) 相同。这就是为什么它不起作用
    • 你自己真的在大型应用程序中使用 add() 吗?
    【解决方案2】:

    我可以建议以下方法:在FragmentBFragmentC 中使用ViewModel 的相同实例(使用活动的ViewModelProvider 创建视图模型实例)与ActionX 事件LiveData。在FragmentC 中设置了LiveData 的值,而FragmentB 观察实时数据变化。

    这里是源代码。

    1.查看模型

    class InterFragmentViewModel : ViewModel() {
        val actionXLiveData = MutableLiveData<Boolean>()
    }
    

    2。片段C

    class FragmentC : AppCompatDialogFragment() {
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            view.findViewById<View>(R.id.action_x).setOnClickListener {
                ViewModelProvider(requireActivity()).get(InterFragmentViewModel::class.java)
                    .actionXLiveData.value = true
            }
        }
    }
    

    3.片段B

    class FragmentB : AppCompatDialogFragment() {
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
    
            ViewModelProvider(requireActivity()).get(InterFragmentViewModel::class.java)
                .actionXLiveData.observe(viewLifecycleOwner, Observer {
                parentFragmentManager.popBackStack()
            })
    
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多