Как закрыть несколько фрагментов в back stack Android
Что проверяют
Знаете ли вы, что back stack фрагментов хранит транзакции, а не сами фрагменты, и умеете ли откатить несколько шагов одной операцией. Следом обычно спрашивают, чем popBackStack() отличается от popBackStackImmediate() и как та же задача решается в Navigation Component.
Как отвечать
Каждый addToBackStack(name) кладёт в стек запись о транзакции. Возврат назад откатывает транзакцию целиком, поэтому несколько экранов закрывают откатом до нужной записи, а не удалением фрагментов:
popBackStack(name, 0): снимает всё выше записи с этим именем, сама запись остаётся;popBackStack(name, FragmentManager.POP_BACK_STACK_INCLUSIVE): снимает и её тоже. Отсюда совет давать транзакциям осмысленные имена;popBackStack(id, flags): то же по идентификатору, который возвращаетcommit()илиgetBackStackEntryAt(i).id;popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE): полная очистка стека, например после выхода из аккаунта.
popBackStack() асинхронный: операция ставится в очередь и выполняется, когда главный поток вернётся в цикл событий. popBackStackImmediate() выполняет её сразу и возвращает true, если что-то сняли. Оба варианта бросают IllegalStateException, если состояние уже сохранено после onSaveInstanceState. Для транзакций рекомендуется setReorderingAllowed(true): при откате нескольких шагов менеджер пропускает промежуточные состояния и лишние вызовы жизненного цикла.
В Navigation Component то же делает navController.popBackStack(R.id.destination, inclusive) или popUpTo с inclusive = true в navOptions, в том числе в Navigation Compose.
Где спотыкаются
Снимают фрагменты циклом с popBackStack() и сразу читают backStackEntryCount. Операции ещё в очереди, счётчик старый, и логика цикла ломается.
Вызывают remove() для фрагмента, добавленного транзакцией со стеком. Запись в back stack остаётся, и нажатие «назад» потом восстанавливает странное состояние экрана.
Оборачивают popBackStack() в beginTransaction() и commit(), как будто откат часть транзакции. Это отдельная операция FragmentManager, а пустой commit() ничего не делает.