У меня есть Fragment A
с RecycleView
, я заменяю его на Fragment B
с помощью FragmentTransaction.replace()
, затем возвращаюсь обратно с popBackStack()
.
onDestroyView()
вызывается на основе документации - после вызова onDestroyView()
новый View
будет создан в следующий раз, когда нужно будет отобразить фрагмент.
Документы:
Вызывается, когда представление, ранее созданное с помощью {@link #onCreateView}, был отделен от фрагмента. В следующий раз, когда фрагменту понадобится для отображения, будет создан новый вид.
Но, позиция RecycleView
сохранена, позиция такая же, когда я оставил эту Fragment
.
Как RecycleView
узнать свое состояние, если новая иерархия представлений в этом фрагменте была раздута, а onSaveInstanceState()
не вызывался?
Представления со значком id+/..
автоматически сохраняются платформой Android и восстанавливаются (где это применимо). Если у представления нет id
, оно не сохраняется (afaicr).
@MartinMarconcini так называется onCreateView()
, раздута новая иерархия представлений, создан новый объект RecycleView
и восстановлено состояние на основе id
? но почему восстановленное состояние срабатывает при обратном нажатии?
Я не уверен, что понимаю ваш вопрос. Вы читали официальную документацию Google о сохранении состояний? Также вы можете взглянуть на исходный код Activity.java, чтобы лучше понять, с чего он начинается. Короче говоря, если есть сохраненное состояние, оно будет восстановлено, поэтому, когда вы наносите ответный удар, вы возвращаетесь к активности, состояние которой было сохранено фреймворком. Вы можете выбрать завершить() действие, если вы этого не хотите.
@MartinMarconcini пример касается фрагментов с одной активностью. so when you hit back, you go back to an activity whose state was saved by the framework
- это что-то новое? активность восстанавливает состояние, когда вы возвращаетесь назад? я думаю ты ошибаешься
Восстановленное состояние относится к входящей активности, а не к уходящей. Когда вы наносите ответный удар, ваша текущая активность уничтожается и завершается(), в этом случае никакое состояние не сохраняется (или не сохраняется), но если ваша последняя активность/фрагмент имеет сохраненное состояние, оно будет восстановлено (с учетом всех правил/ограничений). ).
Как он сохранил состояние и как восстанавливает состояние, если onSaveInstanceState()
не вызывается?
Я полагаю, вы пытаетесь понять, как активность Android «волшебным образом» сохраняет (и восстанавливает) временную иерархию представлений, когда она уничтожается, не заходя и не читая исходный код Activity, где это происходит.
Найдите onSavedInstanceState и просмотрите исходный код. Прочтите Javadocs.
В частности, начните с void onSavedInstanceState(Bundle bundle)
.
Вы заметите, что он говорит (и я цитирую): (выделено мной)
Реализация по умолчанию заботится о большей части состояния пользовательского интерфейса для каждого экземпляра, вызывая {@link android.view.View#onSaveInstanceState()} для каждого представление в иерархии, имеющее идентификатор, и, сохранив идентификатор текущего сфокусированный вид (все это восстанавливается реализацией по умолчанию {@link #onRestoreInstanceState}). Если вы переопределите этот метод, чтобы сохранить дополнительные информацию, не полученную каждым отдельным представлением, вы, вероятно, захотите вызовите реализацию по умолчанию, в противном случае будьте готовы сохранить все состояние каждого представления самостоятельно.
Кроме того, он также говорит, что экземпляр сохранения теперь всегда вызывается, потому что иногда он не нужен...
Одним из примеров, когда вызывается {@link #onPause} и {@link #onStop}, а не этот метод, является переход пользователя от действия B к действию A: нет необходимости вызывать {@link #onSaveInstanceState} для B. потому что этот конкретный экземпляр никогда не будет восстановлен.
Что имеет смысл, вы никогда не вернетесь к действию B (если вы это сделаете, это будет новый экземпляр без сохраненного состояния).
Если вас интересуют мелкие детали, вам придется клонировать исходный код Android и/или просматривать его.
Я не знаю точных деталей реализации, но в основном это сериализация Bundle с примитивными значениями представления (фактическая реализация будет в классе View
, поскольку действие вызывает каждое представление для этого и сохраняет пакет «savedInstanceState» со всем этим информация).
Хуки (или один из них), запускающие такое поведение, находятся в final void performSaveInstanceState(@NonNull Bundle outState)
в действии.
Документ Java совершенно ясен: The hook for {@link ActivityThread} to save the state of this activity.
.
Если вы посмотрите на фактическую реализацию, обратите внимание на вызов onSaveInstanceState
, а затем и saveManagedDialogs
, чтобы сохранить любые диалоги, которые могут быть частью иерархии.
final void performSaveInstanceState(@NonNull Bundle outState) {
dispatchActivityPreSaveInstanceState(outState);
onSaveInstanceState(outState);
saveManagedDialogs(outState);
mActivityTransitionState.saveState(outState);
storeHasCurrentPermissionRequest(outState);
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState);
dispatchActivityPostSaveInstanceState(outState);
}
Он также хранит кучу интересных вещей, mActivityTransitionState
и storeHasCurrentPermissionRequest
. Я не знаю, что именно они делают за кулисами (и, что более важно, как они это делают), но кажется, что это несколько неявно то, что они делают.
Если вас интересуют более подробные сведения, вам придется копнуть глубже самостоятельно или надеяться, что кто-то, у кого больше свободного времени, объяснит точную архитектуру действия. Это интересное упражнение, но не для меня. Это такой большой монолитный класс, что я бы не хотел в него заходить; я имею в виду, мы говорим о классе, который имеет более 8000 строк кода (конечно, много комментариев, но все же).
В деятельности есть много скрытой сложности, много обязанностей, старые методы Java, плохие и хорошие, уникальный стиль кодирования и много волшебства, происходящего за кулисами этими другими «объектами».
Теперь вернемся к вашему вопросу:
Как он сохранил состояние и как он восстанавливает состояние, если onSaveInstanceState() не вызывается?
Activity вызывает свои внутренние методы для сохранения состояния (в пакете), как описано в документации onSaveInstanceState java. Класс большой, и есть множество внутренних/частных методов, которые вызываются в процессе из разных мест, поэтому я не знаю точной архитектуры того, как это организовано (возможно, инженер Google может попытаться объяснить, скорее всего, никто не знает на данный момент больше).
Активность сохранит свое состояние при условии, что представления имеют id
, и она делает это, вызывая каждое представление#onSave... среди прочего; состояние будет восстановлено в onRestoreInstanceState (по активности), если я правильно помню.
Если вы посмотрите на javadocs для onRestore... (выделено мной)
Этот метод вызывается после {@link #onStart}, когда действие повторно инициализируется из ранее сохраненного состояния, указанного здесь в saveInstanceState.
Большинство реализаций будут просто использовать {@link #onCreate} для восстановления своего состояния, но иногда удобно сделать это здесь после того, как вся инициализация была выполнена, или позволить подклассам решить, использовать ли вашу реализацию по умолчанию. Реализация этого метода по умолчанию выполняет восстановление любого состояния представления, которое ранее было заморожено с помощью {@link #onSaveInstanceState}.
Этот метод вызывается между {@link #onStart} и {@link #onPostCreate}. Этот метод вызывается только при воссоздании активности; метод не вызывается, если {@link #onStart} вызывается по любой другой причине.
Так вот как это делают действия. Они точно вызывают onSave/onRestore внутри.
Я нашел интересную информацию в этом другом посте о переполнении стека.
Спасибо за ваше время! Пробовал копаться в исходном коде, оказалось, что FragmentManager
вызывает fragmentStateManager.saveViewState()
и внутренне сохраняет состояние иерархии представлений фрагмента. но View.onSaveInstanceState()
в этой истории используется не View.dispatchSaveInstanceState
. похоже, что View's
также сохраняет свое состояние между транзакциями фрагментов (в дополнение к Activity.onSaveInstanceState()
)
Хорошие дополнения, как видите, все не так просто, как кажется (если речь идет об Android). В любом случае, я совершенно забыл о "фрагментах" в миксе... что, как вы уже видели, представляет собой большую историю!
Я думаю, что если представление ресайклера имеет идентификатор, оно неявно сохраняет свое состояние в пакете. EditText работает так