Давайте посмотрим на методы commit() и commitNow(), которые существуют для управления добавлением или удалением фрагментов из активити. Многие про них знают и слышали, но не все понимают разницу.
Но сначала вспомним что такое транзакция: это последовательность операций, которые выполняются как одно целое. Транзакции помогают убедиться, что все данные остаются правильными, а также предлагают способы справиться с ошибками и вернуться к предыдущему состоянию данных, если что-то пошло не так.
Метод commit() добавляет транзакцию (добавление или удаление фрагмента) в очередь и она будет выполнена асинхронно (параллельно) когда появится возможность. Это значит, что сама транзакция может быть выполнена после того, как метод commit() закончил свою работу.
Метод commitNow() добавляет транзакцию и сразу же выполняет ее, блокируя поток, пока транзакция не будет завершена. Этот метод полезен, если мы хотим выполнить транзакцию синхронно и получить результат сразу же.
Давайте посмотрим на пример кода:
Здесь мы создаем экземпляр MyFragment и добавляем его с помощью метода commit().
Теперь давайте изменим наш код, чтобы использовать метод commitNow():
Здесь мы используем метод commitNow() вместо commit(). Теперь всё, что находится ниже этого кода в методе выполнится строго после завершения транзакции.
Кажется, что тогда лучше использовать всегда commitNow. Но это не так. commit() — более безопасный подход, так как он гарантирует, что все предыдущие транзакции завершатся перед выполнением новой, и обеспечивает правильную последовательность выполнения транзакций. Если мы используем commitNow(), то могут возникнуть конфликты с другими транзакциями, которые ещё не завершились.
Кроме commit и commitNow есть ещё два менее популярных метода:
- commitAllowingStateLoss() — этот метод позволяет выполнить транзакцию даже после того, как состояние активити было сохранено (после вызова onSaveInstanceState()). В отличие от commit(), который бросает исключение IllegalStateException, если его использовать после onSaveInstanceState, commitAllowingStateLoss не вызовет такого исключения. НО! Может произойти ситуация, что у фрагмента потеряется состояние, если система восстановит активити. Это потому что изменения сделанные после onSaveInstanceState не будут в сохраненном Bundle у активити.
- commitNowAllowingStateLoss() — это аналог метода commitNow(), но позволяет выполнить транзакцию даже после того, как состояние активити было сохранено (после вызова onSaveInstanceState()). В остальном он аналогичен commitAllowingStateLoss: тоже не бросает исключение и тоже может потерять состояние фрагмента.
Пример использования метода commitAllowingStateLoss():
Здесь мы используем метод commitAllowingStateLoss() для добавления фрагмента в контейнер.
Пример использования метода commitNowAllowingStateLoss():
Здесь мы используем метод commitNowAllowingStateLoss() для замены фрагмента в контейнере на новый фрагмент.
P.S. Спасибо ChatGPT за помощь с генерацией кодом :)
Дубль статей в телеграмме — https://t.me/android_junior
Мои заметки в телеграмме — https://t.me/android_junior_notes