Как удалить повторяющиеся записи из FragmentManager?

У меня простая деятельность с помощью BottomNavigationView . Я использую фрагменты для реализации содержимого активности для разных страниц.

Когда пользователь нажимает кнопку «Назад», он должен вернуться к ранее просмотренной странице. Проблема в том, что при многократном переходе между страницами (фрагментами) происходит запись всей этой истории. Возьмем следующий пример:

A -> B -> A -> B -> C -> A -> C

Нажатие кнопки «Назад» приведет к обратному, но вместо этого я хочу этого поведения (я заметил это в приложении Instagram):

C -> A -> B -> Exit App

Таким образом, каждый фрагмент должен иметь только одну запись в backstack. Как мне это сделать? Я удаляю предыдущие транзакции для фрагмента из стека?

Возможно ли это с помощью 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)) [email protected] true } R.id.navigation_dashboard -> { // "Dashboard" menu item pressed [email protected] true } R.id.navigation_settings -> { // "Settings" menu item pressed setActiveFragment(resources.getString(R.string.tag_fragment_settings)) [email protected] 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 } } } 

Затем я включил этот класс в свою деятельность:

 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) } } } 
  • Фрагмент как внутренний класс
  • Котлин показал несоответствие типов в фрагменте
  • Изменить фрагмент внутри представления на другое?
  • Значок переполнения Фрагмента по умолчанию
  • Установить LayoutManager на фрагменте
  • Возврат к фрагменту с обратной связью
  • Невозможно добавить фрагменты с помощью функции расширения Kotlin
  • Любое улучшение кода при добавлении / замене фрагмента
  • Android support library 27, Fragment update?
  • Упрощение добавления и замены фрагментов в Котлине
  • Почему скрытие фрагмента вызывает исключение нулевого указателя?
  • Давайте будем гением компьютера.