Pull to refresh

Comments 15

А что насчёт?
setRetainInstance(true);

Биндинг модели во вьюшку — это хорошо, но иногда может быть избыточно.
setRetainInstance(true) не избавляет вас от обязанности сохранять состояние, так как на не помогает в случаях когда Activity была уничтожена и затем восстановлена. Я вообще советую никогда эту опцию не использовать. Разве только в редких случаях, когда восстановление View крайне дорогая операция.
Интересная проблема выискивается после того, как мы откроем другую активити и вернемся назад, а все введенные данные останутся, ибо при открытии и возврате не вызывается метод onCreate.
Не вижу ни какой проблемы. При возвращении в предыдущую Activity она, в большинстве случаев, должна сохранять свое состояние.
Тут дело в том, что даже введенный текст в EditText сохранится, если оставить так как есть.
Если что, в EditText текст сохраняется и без чьей либо помощи. Это уже по умолчанию зашито в самой Activity.

Большинство стандартные компоненты сохраняют свое состояние, если у них есть уникальный ID

Вы пишете, что при убийстве из-за ннхватки памяти нам не нужно сохранять данные.


имхо, правильное поведение, когда пользовиель не знает, что происходило с процессом пока он был в фоне и все его данные сохраняются если он явно не пожелал обратного (например, закрыв активити)

Сейчас пересмотрел код еще раз и заметил, что при наследовании от BaseViewModel вы не определяете новый CREATOR. В таком случае, получается, у вас из Parselable должен восстановиться объект BaseViewModel а не ViewModel. Да и не видно работы с Parcel в самой ViewModel. Это так задумано или ошибка по недосмотру?
Вот тут-то и скрыта самая сильная магия. Так и задумано, это не ошибка. Я, честно скажу, я не знаю почему, но даже в таком виде ViewModel сохраняется полностью. Я пробовал записывать туда массивы, другие объекты, простые типы, все сохраняется даже при пустом CREATOR. Попробуйте запустить этот код и убедитесь. Кто может объяснить почему такое происходит?

Осмелюсь предположить, что на самом деле ничего-то толком и не сохраняется, сохраняется только ссылка на ViewModel, которая потом восстанавливается. В javadoc-ах к Parcel упоминается интересная особенность:


An unusual feature of Parcel is the ability to read and write active
  • objects. For these objects the actual contents of the object is not
  • written, rather a special token referencing the object is written. When
  • reading the object back from the Parcel, you do not get a new instance of
  • the object, but rather a handle that operates on the exact same object that
  • was originally written.

То есть, фактически, ничего не сериализуется, просто если не надо передавать данные меджу процессами (а Parcelable в том числе было сделано для IPC), в целях оптимизации производительности где-то магически держится ссылка на объект ViewModel, который в свою очередь держит ссылки на все объекты внутри себя. Это можно проверить, убив активити (например, свернув его и нажав в Android Studio на панели Android Monitor кнопку "Terminate Application"). Если данные не сериализовались, а просто где-то держалась ссылка на ViewModel, данные не восстановлятся.
Это скорее предположение + немного смутных воспоминаний из своего опыта. Стоит проверить.

Да, действительно. Если включить Don't keep activities, то все летит в нехорошие места. Получается на самом деле нужно реализовывать Creator в классах наследниках. А в таком случае реализовывать Parceble в базовом классе вообще нету смысла.
Никакой тут магии нет. Вы просто эксплуатируете незадокументированное поведение Android API: cистема не сериализует вашу ViewModel при поворотах, а сохраняет во временой переменой. Вся магия начнется когда вы пойдете в настройки, включите Don't keep activities, перейдете на новую Activity, вернетесь назад:

Caused by: java.lang.ClassCastException: com.quinque.aether.reactivemvvm.base.BaseViewModel cannot be cast to com.quinque.aether.reactivemvvm.ViewModel

На самом деле ваше решение ничем не отличается от того чтоб создать статическое поле и туда записывать вашу ViewModel на момент пересоздания Activity. Вся прелесть Parcelable что модель должна выживать даже когда Android убивает вашу Activity.
Спасибо на указание ошибки, поправил код и статью. Стало не так все красиво и уже не без боли, но основная идея все еще видна. Еще буду думать над более изящным решением.

Думаю вам стоит посмотреть в сторону Loaders. Насколько мне известно это сейчас стандратное решение для данной проблемы.

Да нет, что вы, лоадеры помогают в некоторой степени бороться с поворотами, но от нехватки ресурсов все так же не спасают. Я в последнее время решил не бороться с платформой, а подружиться с ней. Фактически, Теперь у меня при убийстве презентеры (у меня MVP, а не MVVM на текущем проекте, но сути это не меняет) умирают и пересоздаются вместе с активити/фрагментами. Все, что надо, сохраняю в Bundle. Как бонус, теперь не нужно проверять, прикреплена ли View к презентеру, потому что они не существуют раздельно, плюс поддерживается восстановление не только при смене ориентации, но и при смерти от нехватки ресурсов.

Скрытый текст
За этим должны следить все приложения, но очень многие об этом либо забывают, либо не заморачиваются. Очень разозлило, когда писал комментарий в Redmine, потом пошел что-то погуглить, и по возвращению увидел, что мой комментарий исчез.


Теоретически может возникнуть ситуация, когда при пересоздании активити восстанавливается слишком много всего, тогда можно отключить пересоздание этой activity и обрабатывать ситуацию вручную (при восстановлении после нехватки памяти время не так критично, потому что пользователь покидал экран/приложение и не ждет моментального отклика) или сделать retain fragment, но на практике мне пока не приходилось такое делать даже на довольно нагруженных экранах.

Sign up to leave a comment.

Articles