В чем разница между commit и commitNow в FragmentManager в Android
Что проверяют
Знаете ли вы, как FragmentManager исполняет транзакции и почему это важно для состояния экрана. Следом обычно спрашивают про IllegalStateException после onSaveInstanceState() и про то, почему commitNow() нельзя совместить с back stack.
Как отвечать
Оба метода работают на главном потоке, разница в моменте исполнения:
commit(): ставит транзакцию в очередь, она выполнится при следующем проходе главного потока. Сразу после вызоваfindFragmentById()фрагмент ещё не вернёт, иonCreateView()у него не вызван. Возвращает идентификатор записи в back stack или отрицательное число, если в стек транзакция не добавлялась;commitNow(): выполняет транзакцию синхронно, к возврату из метода фрагмент уже доведён до состояния хоста. Добавить такую транзакцию в back stack нельзя: вызовaddToBackStack()перед ним приведёт кIllegalStateException;executePendingTransactions(): старый способ ускоритьcommit(). Он выполняет все отложенные транзакции разом, включая чужие, поэтомуcommitNow()предпочтительнее, когда нужно применить ровно одну;- варианты
...AllowingStateLoss(): есть у обоих методов. Позволяют закоммитить после сохранения состояния, но изменение может потеряться при пересоздании активити или процесса.
Практическое правило: по умолчанию commit() вместе с setReorderingAllowed(true), а commitNow() там, где следующей строкой нужен результат, например для фрагмента без интерфейса или в тесте.
Где спотыкаются
Говорят, что commit() выполняется асинхронно в фоне и потому не блокирует интерфейс. Фонового потока здесь нет, обе транзакции исполняются на главном, отличается только момент.
Коммитят один и тот же объект FragmentTransaction дважды. Транзакция одноразовая, повторный вызов бросит IllegalStateException, для второй операции нужен новый beginTransaction().
Зовут commitNow() из колбэка жизненного цикла другого фрагмента, пока FragmentManager ещё исполняет транзакцию, и получают исключение о том, что менеджер уже занят. Решение обычно в том, чтобы вынести операцию из колбэка или обойтись обычным commit().