Android 如何从FragmentManager中删除重复条目?
我有一个带有Android 如何从FragmentManager中删除重复条目?,android,android-fragments,kotlin,Android,Android Fragments,Kotlin,我有一个带有BottomNavigationView的简单活动。我使用片段来实现不同页面的活动内容 当用户按下后退按钮时,应该返回到之前查看的页面。问题是,当您在页面(片段)之间反复切换时,整个历史记录都会被记录下来。举个例子: A->B->A->B->C->A->C 按“后退”按钮会产生相反的结果,但我想要这种行为(我在Instagram应用程序中注意到): C->A->B->退出应用程序 因此,每个片段在backbackback中应该只有一个条目。我该怎么做?我是否从堆栈中删除片段的先前事务
BottomNavigationView
的简单活动。我使用片段来实现不同页面的活动内容
当用户按下后退按钮时,应该返回到之前查看的页面。问题是,当您在页面(片段)之间反复切换时,整个历史记录都会被记录下来。举个例子:
A->B->A->B->C->A->C
按“后退”按钮会产生相反的结果,但我想要这种行为(我在Instagram应用程序中注意到):
C->A->B->退出应用程序
因此,每个片段在backbackback中应该只有一个条目。我该怎么做?我是否从堆栈中删除片段的先前事务
使用FragmentManager是否可以实现这一点?还是我必须实施我自己的
使用BottomNavigationView的我的活动:
class ActivityOverview : AppCompatActivity() {
// Listener for BottomNavigationView
private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.navigation_home -> {
// "Home" menu item pressed
setActiveFragment(resources.getString(R.string.tag_fragment_home))
return@OnNavigationItemSelectedListener true
}
R.id.navigation_dashboard -> {
// "Dashboard" menu item pressed
return@OnNavigationItemSelectedListener true
}
R.id.navigation_settings -> {
// "Settings" menu item pressed
setActiveFragment(resources.getString(R.string.tag_fragment_settings))
return@OnNavigationItemSelectedListener true
}
}
false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_overview)
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
navigation.menu.findItem(R.id.navigation_home).setChecked(true)
// Set initial fragment
setActiveFragment(resources.getString(R.string.tag_fragment_home))
}
override fun onBackPressed() {
// > 1 so initial fragment addition isn't removed from stack
if (fragmentManager.backStackEntryCount > 1) {
fragmentManager.popBackStack()
} else {
finish()
}
}
// Update displayed fragment
fun setActiveFragment(tag: String) {
val fragment = if (fragmentManager.findFragmentByTag(tag) != null) {
// Fragment is already initialized
if (fragmentManager.findFragmentByTag(tag).isVisible) {
// Fragment is visible already, don't add another transaction
null
} else {
// Fragment is not visible, add transaction
fragmentManager.findFragmentByTag(tag)
}
} else {
// Fragment is not initialized yet
when (tag) {
resources.getString(R.string.tag_fragment_home) -> FragmentHome()
resources.getString(R.string.tag_fragment_settings) -> FragmentSettings()
else -> null
}
}
if (fragment != null) {
val transaction = fragmentManager.beginTransaction()
transaction.replace(R.id.container_fragment, fragment, tag)
transaction.addToBackStack(null)
transaction.commit()
}
}
}
此时,我非常确定FragmentManager不起作用,因此我创建了一个类来实现不允许重复的堆栈:
class NoDuplicateStack<T> {
val stack: MutableList<T> = mutableListOf()
val size: Int
get() = stack.size
// Push element onto the stack
fun push(p: T) {
val index = stack.indexOf(p)
if (index != -1) {
stack.removeAt(index)
}
stack.add(p)
}
// Pop upper element of stack
fun pop(): T? {
if (size > 0) {
return stack.removeAt(stack.size - 1)
} else {
return null
}
}
// Look at upper element of stack, don't pop it
fun peek(): T? {
if (size > 0) {
return stack[stack.size - 1]
} else {
return null
}
}
}
类节点重复堆栈{
val堆栈:MutableList=mutableListOf()
val大小:Int
get()=stack.size
//将元素推到堆栈上
趣味推送(p:T){
val index=stack.indexOf(p)
如果(索引!=-1){
stack.removeAt(索引)
}
stack.add(p)
}
//弹出堆栈的上部元素
有趣的流行音乐:T{
如果(大小>0){
返回stack.removeAt(stack.size-1)
}否则{
返回空
}
}
//查看堆栈的上部元素,不要将其弹出
有趣的偷看:T{
如果(大小>0){
返回堆栈[stack.size-1]
}否则{
返回空
}
}
}
然后,我将该课程整合到我的活动中:
class ActivityOverview : AppCompatActivity() {
val fragmentsStack = NoDuplicateStack<String>()
val fragmentHome = FragmentHome()
val fragmentSettings = FragmentSettings()
val fragmentHistory = FragmentHistory()
// Listener for BottomNavigationView
private val mOnNavigationItemSelectedListener = ...
override fun onCreate(savedInstanceState: Bundle?) {
...
}
override fun onBackPressed() {
if (fragmentsStack.size > 1) {
// Remove current fragment from stack
fragmentsStack.pop()
// Get previous fragment from stack and set it again
val newTag = fragmentsStack.pop()
if (newTag != null) {
setActiveFragment(newTag)
}
} else {
finish()
}
}
// Update displayed fragment
fun setActiveFragment(tag: String) {
val fragment = when (tag) {
resources.getString(R.string.tag_fragment_home) -> fragmentHome
resources.getString(R.string.tag_fragment_settings) -> fragmentSettings
resources.getString(R.string.tag_fragment_history) -> fragmentHistory
else -> null
}
if (fragment != null && !fragment.isVisible) {
fragmentManager.beginTransaction()
.replace(R.id.container_fragment, fragment, tag)
.commit()
fragmentsStack.push(tag)
}
}
}
类活动概述:AppCompatActivity(){
val fragmentsStack=NoDuplicateStack()
val fragmentHome=fragmentHome()
val fragmentSettings=fragmentSettings()
val fragmentHistory=fragmentHistory()
//BottomNavigationView的侦听器
private val mOnNavigationItemSelectedListener=。。。
重写创建时的乐趣(savedInstanceState:Bundle?){
...
}
重写函数onBackPressed(){
如果(碎片堆栈大小>1){
//从堆栈中删除当前片段
fragmentsStack.pop()
//从堆栈中获取上一个片段并再次设置它
val newTag=fragmentsStack.pop()
如果(newTag!=null){
setActiveFragment(新标记)
}
}否则{
完成()
}
}
//更新显示的片段
fun setActiveFragment(标记:String){
val fragment=when(标记){
resources.getString(R.string.tag\u fragment\u home)->fragmentHome
resources.getString(R.string.tag\u fragment\u settings)->fragmentSettings
resources.getString(R.string.tag\u fragment\u history)->fragmentHistory
else->null
}
if(fragment!=null&&!fragment.isVisible){
fragmentManager.beginTransaction()
.替换(R.id.container_碎片、碎片、标签)
.commit()
碎片堆叠推送(标签)
}
}
}
我也面临同样的问题,我使用了系统堆栈来解决这个问题
val totalFragments = supportFragmentManager.backStackEntryCount
if (totalFragments != 0) {
val removed = supportFragmentManager.getBackStackEntryAt(totalFragments - 1)
poppedFragments.add(removed.name!!)
for (idx in totalFragments - 1 downTo 0) {
val fragment = supportFragmentManager.getBackStackEntryAt(idx)
if (!poppedFragments.contains(fragment.name)) {
supportFragmentManager.popBackStack(fragment.name, 0)
return
}
}
finish()
return
}
super.onBackPressed()
然后在启动碎片时添加了这个
if (poppedFragments.contains(tag)) {
poppedFragments.remove(tag)
}
直觉反应是:每次添加一个片段时,在片段管理器中查找它,如果它在那里,则将其删除(使用
FragmentTransaction.remove()
)。这样,您的片段管理器中只有一个给定片段的实例,最新的实例位于顶部。@BenP。但是我如何检索实际的事务,而不仅仅是片段?我有与您在问题中提到的相同的确切要求。我正在尝试实现您的解决方案,但是考虑到我使用的是java而不是kotlin,我无法实现与您使用的完全相同的逻辑。您是否也可以提供与java兼容的解决方案?