用于替换或删除 backstack 上现有片段的代码不起作用

Code to replace or remove existing fragment on backstack not working

我正在使用 Actionbar,我在应用栏中有一个图标,单击该图标会转到 CategoryFragment。但我想这样做,如果该片段已经在后台,它应该删除它,然后将 CategoryFragment 的新实例添加到后台或替换它。

我尝试了下面的代码,但它不起作用,并且只在现有的 CategoryFragment 之上 overlays/superimposes 另一个 CategoryFragment 的副本,并且还会产生非常奇怪和意外的行为。我没有使用 navcontroller 导航到 CategoryFragment,因为它在后台堆栈中添加了片段的另一个副本。我怎样才能完成这项工作?

主要 Activity:

中的 onOptionsItemSelected()
override fun onOptionsItemSelected(item: MenuItem): Boolean {

        Log.i("Lifecycle-Activity", "OnOptionsItemSelected() called")

         when (item.itemId) {
                android.R.id.home -> {
                        onBackPressed()
                        return true
                }

               R.id.categoryFragment -> {

                    var backStateName = CategoryFragment::class.simpleName

                    var fragmentPopped = supportFragmentManager.popBackStackImmediate(backStateName, 0)

                    if(!fragmentPopped)
                    {
                        var ft = supportFragmentManager.beginTransaction()

                        //also tried R.id.main_activity_container which is not working
                        ft.replace(R.id.navHostFragment, CategoryFragment())

                        ft.addToBackStack(backStateName)
                        ft.commit()
                    }

                    return true
                }
    return true
    }

主要Activity

  class MainActivity : AppCompatActivity() {

        private lateinit var appBarConfiguration: AppBarConfiguration

        private lateinit var navController: NavController

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.main_activity)

            Log.i("Lifecycle-Activity", "OnCreate() called")

            navController = Navigation.findNavController(this, R.id.navHostFragment)

            NavigationUI.setupActionBarWithNavController(this, navController)

            appBarConfiguration = AppBarConfiguration.Builder(navController.graph)
                .build()
        }

        override fun onSupportNavigateUp(): Boolean {

    super.onSupportNavigateUp()

            return NavigationUI.navigateUp(navController, appBarConfiguration)

        }

        override fun onCreateOptionsMenu(menu: Menu?): Boolean {

            Log.i("Lifecycle-Activity", "OnCreateOptionsMenu() called")

            menuInflater.inflate(R.menu.main_menu, menu)
            return super.onCreateOptionsMenu(menu)
        }

        override fun onOptionsItemSelected(item: MenuItem): Boolean {

            Log.i("Lifecycle-Activity", "OnOptionsItemSelected() called")
 when (item.itemId) {
            android.R.id.home -> {
                    onBackPressed()
                    return true
            }

  R.id.categoryFragment -> {

                var backStateName = CategoryFragment::class.simpleName

                var fragmentPopped = supportFragmentManager.popBackStackImmediate(backStateName, 0)

                if(!fragmentPopped)
                {
                    var ft = supportFragmentManager.beginTransaction()

                    //also tried R.id.main_activity_container which is not working
                    ft.replace(R.id.navHostFragment, CategoryFragment())

                    ft.addToBackStack(backStateName)
                    ft.commit()
                }

            }

           return true
        }
return true
}

导航图:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph_main"
    app:startDestination="@id/categoriesFragment">
    <fragment
        android:id="@+id/clockFragment"
        android:name="com.example.pomoplay.ui.main.ClockFragment"
        android:label="Pomo Clock"
        tools:layout="@layout/fragment_clock" />
    <fragment
        android:id="@+id/categoryFragment"
        android:name="com.example.pomoplay.ui.main.CategoryFragment"
        android:label="Category"
        tools:layout="@layout/fragment_category">
        <action
            android:id="@+id/action_open_category_fragment"
            app:destination="@id/categoryFragment"
            app:popUpTo="@id/categoryFragment"
            app:popUpToInclusive="true" />
        <action
            android:id="@+id/action_categoryFragment_to_clockFragment"
            app:destination="@id/clockFragment" />
        <action
            android:id="@+id/action_categoryFragment_to_newTaskDialogFragment"
            app:destination="@id/newTaskDialogFragment" />
        <argument
            android:name="category"
            app:argType="com.example.pomoplay.Category" />
    </fragment>
    <fragment
        android:id="@+id/categoriesFragment"
        android:name="com.example.pomoplay.ui.main.CategoriesFragment"
        android:label="Categories"
        tools:layout="@layout/fragment_categories">
        <action
            android:id="@+id/action_categoriesFragment_to_newCategoryDialogFragment"
            app:destination="@id/newCategoryDialogFragment" />
        <argument
            android:name="category"
            app:argType="com.example.pomoplay.Category" />
        <action
            android:id="@+id/action_categoriesFragment_to_categoryFragment"
            app:destination="@id/categoryFragment" />
        <argument
            android:name="fromNewCategoryDialog"
            app:argType="boolean"
            android:defaultValue="false" />
    </fragment>
    <dialog
        android:id="@+id/newCategoryDialogFragment"
        android:name="com.example.pomoplay.ui.main.NewCategoryDialogFragment"
        tools:layout="@layout/fragment_new_category_dialog">
        <action
            android:id="@+id/action_newCategoryDialogFragment_to_categoriesFragment"
            app:destination="@id/categoriesFragment"
            app:popUpToInclusive="false" />
    </dialog>
    <dialog
        android:id="@+id/newTaskDialogFragment"
        android:name="com.example.pomoplay.ui.main.NewTaskDialogFragment"
        android:label="fragment_new_task_dialog"
        tools:layout="@layout/fragment_new_task_dialog" >
        <action
            android:id="@+id/action_newTaskDialogFragment_to_categoryFragment"
            app:destination="@id/categoryFragment"
            app:popUpTo="@+id/categoryFragment"
            app:popUpToInclusive="true" />
    </dialog>
</navigation>

您正在使用 NavController,因此您根本不应该进行任何手动操作 FragmentTransaction

相反,您应该 Navigation to a destination, in this case, by using Navigation's support for popUpTo 将您的 CategoryFragment 从堆栈中弹出。

假设您在导航 XML 中为您的 CategoryFragment 设置了目的地,代码如下:

<fragment
    android:id="@+id/categoryFragment"
    android:name=".CategoryFragment/>

您可以 create an action 包含您需要的 popUpTo 标志(您可以将其直接放在 <fragment> 本身的下方:

<action
    android:id+"@+id/open_category"
    app:popUpTo="@id/categoryFragment"
    app:popUpToInclusive="true"
    app:destination="@id/categoryFragment"/>

这表示:

  1. 创建一个名为 open_category

  2. 的动作
  3. 当您触发此操作时,如果堆栈已存在于返回堆栈中,则将堆栈弹出回 categoryFragment(否则,此操作不执行任何操作)。 popUpToInclusive 表示弹出前一个实例。

  4. 弹出前一个实例后,创建 categoryFragment 的新实例并将其添加到返回堆栈。

然后您可以从 onOptionsItemSelected()':

触发该操作
override fun onOptionsItemSelected(item: MenuItem): Boolean {

    Log.i("Lifecycle-Activity", "OnOptionsItemSelected() called")

    return when (item.itemId) {
        R.id.categoryFragment -> {
            // Trigger the action
            navController.navigate(R.id.open_category);
            true
       }
       default -> {
           // android.R.id.home is handled by the call to super,
           // you do not need to handle it here.
           super.onOptionsItemSelected(item)
       }
    }
}