В чем разница между commit и commitNow во фрагментах Android
Что проверяют
Понимаете ли вы, как FragmentManager выполняет транзакции и почему фрагмент сразу после commit() ещё не находится через findFragmentByTag. Следом почти всегда спрашивают про back stack и про IllegalStateException после onSaveInstanceState.
Как отвечать
Оба метода выполняют транзакцию на главном потоке, разница только в моменте:
commit(): ставит транзакцию в очередьFragmentManager, она выполнится на ближайшем проходе главного цикла, уже после текущего кода. Транзакции применяются строго по порядку, метод возвращает идентификатор записи в back stack;commitNow(): синхронно выполняет только эту транзакцию. К возврату из метода фрагмент уже добавлен и доведён до состояния хоста. Возвращаетvoid;executePendingTransactions(): синхронно выполняет всю очередь. Документация советуетcommitNow()вместо парыcommit()плюсexecutePendingTransactions(), потому что второй вариант заодно проталкивает все чужие отложенные транзакции.
Главное ограничение: commitNow() несовместим с addToBackStack(), такая транзакция бросит IllegalStateException. Синхронное выполнение сломало бы порядок записей в стеке относительно тех, что ещё стоят в очереди. Ещё его нельзя вызывать, пока FragmentManager сам выполняет транзакции, например из колбэка жизненного цикла фрагмента.
Когда что брать: навигация с кнопкой «Назад» идёт через commit() (Navigation Component делает это за вас). commitNow() нужен, когда результат требуется следующей строкой: фрагмент без UI, настройка экрана в onCreate, тесты.
Где спотыкаются
Говорят, что commit() выполняется в фоновом потоке и поэтому не блокирует UI. Работа всё равно идёт на главном потоке, просто чуть позже.
Вызывают commitNow() вместе с addToBackStack() и удивляются падению.
Лечат ошибку после onSaveInstanceState заменой на commitAllowingStateLoss() везде подряд. Правильнее не делать транзакции из асинхронных колбэков, когда экран уже ушёл в фон: иначе изменения молча пропадут при восстановлении активити.