Как внутри работает новая функция FragmentTransaction commitNow ()?

Добавлен новый метод commitNow () в Android N и версии библиотеки поддержки 24 имеется ограниченная и немного запутанная документация.

Выполняет эту транзакцию синхронно. Любые добавленные фрагменты будут инициализированы и полностью переведены в состояние жизненного цикла своего хоста, а любые удаленные фрагменты будут соответственно удалены до того, как этот вызов вернется. Фиксация транзакции таким образом позволяет добавлять фрагменты в виде выделенных инкапсулированных компонентов, которые отслеживают состояние жизненного цикла своего хоста, обеспечивая при этом более жесткие гарантии упорядочения, когда эти фрагменты полностью инициализированы и готовы. Эти представления будут созданы и прикреплены к фрагментам, которые управляют представлениями.

Вызов commitNow предпочтительнее, чем вызов commit (), за которым следует FragmentManager.executePendingTransactions (), поскольку последний будет иметь побочный эффект попытки зафиксировать все текущие ожидающие транзакции, независимо от того, является ли это желаемым поведением или нет.

Транзакции, совершенные таким образом, не могут быть добавлены в задний стек FragmentManager, поскольку это нарушит другие ожидаемые гарантии упорядочения для других асинхронно зафиксированных транзакций. Этот метод вызовет исключение IllegalStateException, если транзакция ранее запрашивалась для добавления в задний стек с помощью addToBackStack (String).

Транзакция может быть зафиксирована с помощью этого метода только до того, как содержащееся в ней действие сохранит свое состояние. Если попытка фиксации предпринята после этого момента, будет выдано исключение. Это связано с тем, что состояние после фиксации может быть потеряно, если действие необходимо восстановить из своего состояния. См. CommitAllowingStateLoss () для ситуаций, когда можно потерять фиксацию.

Я выделил жирным шрифтом ту часть, которая, на мой взгляд, сбивает с толку.

Итак, мои основные проблемы / вопросы:

1 - Они НЕ МОГУТ быть добавлены? В нем говорится, что я получу исключение IllegalStateException, так будет ли оно добавлено или не будет?

2 - Я принимаю тот факт, что я не могу использовать это, если мы хотим добавить фрагмент в backstack. Здесь не говорится, что вы получаете это исключение:

java.lang.IllegalStateException: This transaction is already being added to the back stack

!!!!????

Значит, я не могу позвонить addToBackStack(String) сам, потому что он внутренне звонит мне? Прошу прощения, но ... что? Почему? что, если я не хочу, чтобы он добавлялся в backstack? А что, если я попытаюсь использовать этот фрагмент из бэкстека позже, но, поскольку он НЕ МОЖЕТ быть добавлен, позже его там нет?

Похоже, этого можно было ожидать, если бы я использовал commitAllowingStateLoss(), но я вижу, что commitNowAllowingStateLoss() тоже существует, так что ... какой логике это следует?

TL;DR

Как commitNow () внутренне работает с backstack?


person Kaizie    schedule 25.07.2016    source источник
comment
И вот, 5 месяцев спустя, до сих пор никто не знает!   -  person EpicPandaForce    schedule 08.12.2016
comment
@EpicPandaForce ответил! Надеюсь, мой ответ удовлетворит вас :)   -  person Niko Adrianus Yuwono    schedule 09.12.2016
comment
@NikoAdrianusYuwono Я немного подольше назначу награду, чтобы убедиться, но это определенно начало: p   -  person EpicPandaForce    schedule 09.12.2016
comment
@EpicPandaForce Нет проблем! Сообщите мне, если у вас останутся неясные моменты! Всегда приятно ответить на такой вопрос, когда мне нужно покопаться в исходном коде Android;)   -  person Niko Adrianus Yuwono    schedule 09.12.2016


Ответы (2)


Когда мы столкнулись с таким вопросом, это хорошо, что исходный код Android является открытым исходным кодом!

Отвечать

Итак, давайте взглянем на исходный код BackStackRecord здесь

@Override
public void commitNow() {
    disallowAddToBackStack();
    mManager.execSingleAction(this, false);
}

@Override
public FragmentTransaction disallowAddToBackStack() {
    if (mAddToBackStack) {
        throw new IllegalStateException(
                "This transaction is already being added to the back stack");
    }
    mAllowAddToBackStack = false;
    return this;
}

И mAddToBackStack будет установлено значение true, если вы вызовете addToBackStack в своей транзакции.

Итак, чтобы ответить на ваш вопрос, no addToBackStack не вызывается изнутри, когда вы вызываете commitNow(). Это сообщение об исключении, которое неоднозначно. Я думаю, он должен сказать You're not allowed to add to backstack when using commitNow() вместо текущего сообщения.

Бонус:

Если мы углубимся в исходный код FragmentManager, здесь, commitNow() фактически выполняет почти то же самое, что и executePendingTransactions(), как написано выше, но вместо выполнения всех ранее зафиксированных транзакций, commitNow () зафиксирует только эту транзакцию.

Я думаю, что это основная причина, по которой commitNow () не разрешает добавление в backstack, поскольку не может гарантировать отсутствие других ожидающих транзакций. Если commitNow () может добавить в backstack, есть вероятность, что мы сможем нарушить нашу последовательность backstack, что приведет к неожиданным вещам.

person Niko Adrianus Yuwono    schedule 09.12.2016
comment
Да, проверяя исходный код, похоже, что это правильный ответ. Но почему-то мне кажется, что они переоценили этот новый API в Google IO ... потому что они пытались продать его как потрясающее решение проблемы фрагментов IllegalStateException после паузы активности, но почему-то это не предлагает полные функции commit (), потому что вы не можете добавить его в backstack ... поэтому его можно использовать только в определенных ситуациях, если ваше приложение позволяет добавлять этот фрагмент без добавления его в backstack ... В любом случае, правильный ответ! Спасибо! - person Kaizie; 12.12.2016
comment
@Kaizie Спасибо! Да, как и то, что я написал выше, будет вероятность создания неправильного / неожиданного порядка backstack, если добавление через commitNow () добавит в backstack. Давайте подождем, пока Google, возможно, у них есть другое решение: D Или, может быть, если я смогу придумать лучшие способы, снова прокомментирую этот ответ! - person Niko Adrianus Yuwono; 12.12.2016
comment
См. Также nikoyuwono.com/2016/12/13/fragment-transaction-commitnow.. - person CoolMind; 01.07.2019

Короче,

Если вы используете addToBackStack() с Fragment, не используйте commitNow() вместо этого используйте commit().

Использование Fragment с addToBackStack() и commitNow() приводит к несогласованному упорядочиванию транзакций фрагментов и, следовательно, необходимо использовать commit().

Подробное описание см. В этой статье

person iCantC    schedule 06.03.2020