替换或删除后台堆栈上现有片段的代码不起作用
Posted
技术标签:
【中文标题】替换或删除后台堆栈上现有片段的代码不起作用【英文标题】:Code to replace or remove existing fragment on backstack not working 【发布时间】:2020-05-19 11:41:06 【问题描述】:我正在使用Actionbar
,并且我在应用栏中有一个图标,单击该图标应转到CategoryFragment
。但我想这样做,如果该片段已经在后台堆栈上,它应该删除它,然后将 CategoryFragment
的新实例添加到后台堆栈或替换它。
我尝试了下面的代码,但它不起作用,只会在现有的CategoryFragment
之上覆盖/叠加CategoryFragment
的另一个副本,并且还会产生非常奇怪和意外的行为。我没有使用导航控制器导航到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
主要活动
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>
【问题讨论】:
【参考方案1】:您正在使用NavController
,因此您根本不应该手动操作FragmentTransaction
s。
相反,您应该 Navigation to a destination,在这种情况下,通过使用 Navigation 对 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)
【讨论】:
我完全按照您的说明进行操作,但是当我单击应用栏菜单图标时,应用程序崩溃并显示以下错误消息:navigation destination com.example.pomoplay:id/action_open_category_fragment is unknown to this NavController
。可能是什么问题?
您的解决方案似乎仅在当前可见片段为CategoryFragment
时才有效。如果当前可见片段是不同的片段,则单击 ActionBar
中的菜单图标会导致应用程序崩溃并显示以下错误消息:navigation destination com.example.pomoplay:id/action_open_category_fragment is unknown to this NavController
似乎您将操作 within 放在 <fragment>
标记中,而不是在其下方。他们应该在同一级别
我就是这样。我把动作放在它下面。在<fragment>
的/>
结束标记之后。但是,它仍然会因该错误消息而崩溃。
能否在问题中包含导航 XML?以上是关于替换或删除后台堆栈上现有片段的代码不起作用的主要内容,如果未能解决你的问题,请参考以下文章