用于替换或删除 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"/>
这表示:
创建一个名为 open_category
的动作
当您触发此操作时,如果堆栈已存在于返回堆栈中,则将堆栈弹出回 categoryFragment
(否则,此操作不执行任何操作)。 popUpToInclusive
表示弹出前一个实例。
弹出前一个实例后,创建 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)
}
}
}
我正在使用 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"/>
这表示:
创建一个名为
open_category
的动作
当您触发此操作时,如果堆栈已存在于返回堆栈中,则将堆栈弹出回
categoryFragment
(否则,此操作不执行任何操作)。popUpToInclusive
表示弹出前一个实例。弹出前一个实例后,创建
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)
}
}
}