#android-activity #android
#android-активность #Android
Вопрос:
Я читаю эту статью о том, как: правильно сохранять переменное состояние в Android, и мне напоминают, что я никогда не получал хорошего ответа (и не могу найти его здесь), почему лучше бороться с пакетом (что не является БОЛЬШОЙ проблемой, но определенно имеет свои ограничения), а нечем просто всегда переопределять приложение в вашем приложении и просто хранить там все ваши постоянные элементы данных. Есть ли риск утечки? Есть ли способ, которым память может быть неожиданно освобождена? Я просто не понимаю этого … кажется, что это абсолютно надежный «чердак» для всех действий и идеальное место для хранения всего, что, как вы беспокоитесь, может быть сброшено, когда пользователь включает устройство или приостанавливает работу приложения.
Я ошибаюсь в этом? Хотелось бы получить некоторую ясность в отношении того, каков истинный жизненный цикл памяти в приложении.
Основываясь на приведенных ниже ответах, позвольте мне расширить свой вопрос.
Предположим, у меня есть приложение, которое ведет себя по-разному на основе XML-файла, который он загружает при запуске.
В частности, приложение представляет собой приложение для сбора пользовательской информации, и в зависимости от настроек XML оно будет следовать по множеству открытых путей (сбор информации A, но не J, и предложение опроса P, За которым следует дополнительная возможность фотографирования и т. Д.)
В идеале мне не нужно хранить детали этого пути поведения в пакете (не дай бог) или в базе данных (тоже некрасиво, но в меньшей степени). Я бы загрузил XML, обработал его и заставил приложение удерживать эту структуру, чтобы я мог ссылаться на него, чтобы узнать, что делать дальше и как. Если приложение приостановлено и приложение выпущено, не так уж сложно проверить наличие null в моем объекте CustomFlow (который генерируется в соответствии с XML) и повторно создать его экземпляр. В любом случае, не похоже, что это будет происходить так часто. Будет ли это хорошим примером того, где приложение является * лучшим инструментом?
Комментарии:
1. Учитывая ваше описание, я бы полностью согласился с вашим редактированием.
2. Нет проблем. Как все здесь подчеркивали, это зависит от того, как все это используется. Ваш пример был отличным, потому что он выводит данные времени выполнения из состояния времени выполнения и позволяет вашим компонентам инициировать действие на основе этих данных, а не событий.
Ответ №1:
Вопрос о том, какой метод лучше, во многом зависит от того, какую информацию вы храните и к какой информации вам нужен доступ, И кому (какие компоненты, пакеты и т. Д.) Нужен доступ к этой информации. Кроме того, такие настройки, как launchMode
и configChanges
которые изменяют жизненный цикл, могут помочь вам определить, какой метод лучше для вас.
Во-первых, позвольте мне отметить, что я большой сторонник расширения объекта приложения и часто расширяю класс приложения, но принимаю все изложенное здесь в его контексте, поскольку важно понимать, что бывают обстоятельства, когда это просто не выгодно.
О жизненном цикле приложения: Чаббард в основном правильно указал, что приложение имеет тот же срок службы, что и одноэлементный компонент. Хотя они очень близки, есть некоторые незначительные различия. Само приложение ОБРАБАТЫВАЕТСЯ ОС как синглтон и работает до тех пор, пока работает ЛЮБОЙ компонент, включая AppWidget (который может существовать в другом приложении) или ContentResolver.
Все ваши компоненты в конечном итоге обращаются к одному и тому же объекту, даже если они находятся в нескольких задачах или процессах. Однако это не гарантирует, что так будет продолжаться вечно (поскольку приложение на САМОМ деле не является синглтоном), и гарантируется только в Google Android, а не в переопределенных производителем версиях. Это означает, что определенные вещи должны обрабатываться с осторожностью внутри объекта приложения.
Ваш Application
объект не умрет, если все ваши компоненты также не будут уничтожены. Тем не менее, Android имеет возможность отключить любое количество компонентов. Это означает, что вам никогда не гарантируется наличие Application
объекта, но если какой-либо из ваших компонентов активен, есть Application
с чем его связать.
Еще одна приятная особенность Application
заключается в том, что он не привязан к запущенным компонентам. Однако ваши компоненты привязаны к нему, что делает его чрезвычайно полезным.
Чего следует избегать в объекте приложения:
- Как обычно, избегайте статических
Context
файлов. На самом деле, часто вам вообще не следует хранить aContext
здесь, потомуApplication
что этоContext
само по себе. - Большинство методов здесь должны быть статическими, потому что вы не гарантированно получите тот же
Application
объект, хотя это очень вероятно. - Если вы переопределите
Application
, тип ваших данных и методов, хранящихся здесь, поможет вам в дальнейшем определить, нужно ли вам создавать одноэлементный компонент или нет. Drawables
и его производные, скорее всего, «утекут», если о них не позаботятся, поэтому также рекомендуется избегать ссылок наDrawables
here.- Состояние выполнения любого отдельного компонента. Это потому, что, опять же, вы не гарантированно получите тот же
Application
объект. Кроме того, здесь не доступно ни одно из событий жизненного цикла, которые происходят в anActivity
.
Что нужно хранить в приложении (поверх пакета)
Это Application
отличное место для хранения данных и методов, которые должны быть разделены между компонентами, особенно если у вас несколько точек входа (несколько компонентов, которые можно запускать и запускать помимо действия запуска). Application
Например, во всех моих файлах я размещаю свои теги ОТЛАДКИ и код журнала.
Если у вас есть ContentProvider или BroadcastReceiver, это делает Application
его еще более идеальным, потому что они имеют небольшие жизненные циклы, которые не являются «возобновляемыми», как Activity
or AppWidgetProvider
, и теперь могут получить доступ к этим данным или методам.
Настройки используются для определения, как правило, параметров запуска при нескольких запусках, поэтому это может быть отличным местом для обработки SharedPreferences
, например, с одним доступом, а не по одному на компонент. На самом деле, все, что «сохраняется» при нескольких запусках, отлично подходит для доступа здесь.
Наконец, одним из основных упущенных преимуществ является то, что вы можете хранить и упорядочивать свои константы здесь без необходимости загружать другой класс или объект, потому что ваш Application
всегда выполняется, если один из ваших компонентов. Это особенно полезно для намеренных действий и сообщений об исключениях и других подобных типов констант.
Что нужно хранить в пакете, а не в состоянии выполнения приложения, которое зависит от наличия или состояния одного компонента или выполнения одного компонента. Кроме того, все, что зависит от состояния отображения, ориентации или аналогичных сервисов Android, здесь не является предпочтительным. Это потому Application
, что никогда не уведомляется об этих изменениях. Наконец, все, что зависит от уведомления от этой системы Android, не должно размещаться здесь, например, реакция на события жизненного цикла.
И…. В другом месте
Что касается других данных, которые необходимо сохранить, у вас всегда есть базы данных, сетевые серверы и файловая система. Используйте их так, как вы всегда делали бы.
Каким бы полезным и недооцененным Application
оно ни было, хорошее понимание важно, поскольку оно не идеально. Надеюсь, эти разъяснения дадут вам некоторое представление о том, почему гуру поощряют один способ, а не другой. Поймите, что у многих разработчиков схожие потребности, и большая часть инструкций основана на тех методах и знаниях, которыми обладает большинство сообщества. Ничто из того, что говорит Google, не относится ко всем потребностям программиста, и есть причина, по которой приложение не было объявлено Final
.
Помните, что есть причина, по которой Android должен иметь возможность уничтожать ваши компоненты. И основная причина — это память, а не обработка. Используя приложение, как описано выше, и разрабатывая соответствующие методы для сохранения соответствующей информации, вы можете создавать более надежные приложения, которые учитывают требования системы, пользователя, его родственных компонентов и других разработчиков. Использование информации, которую все здесь предоставили, должно дать вам отличные рекомендации относительно того, как и когда расширять свой Application
.
Надеюсь, это поможет, FuzzicalLogic
Комментарии:
1. Ммм, я должен подать жалобу на ваш последний абзац. Я ничего не заставляю в памяти. Я поддерживаю многое из того, что вы сделали для приложения, поскольку его часто упускают из виду как инструмент, облегчающий вашу жизнь. В отличие от создания одиночек, которые сделают вашу жизнь несчастной из-за ужасных проблем с зависимостями и вообще не смогут напрямую участвовать в жизненном цикле. Если ваше приложение восстанавливается, я ничего не сказал, что может предотвратить это. Но я предложил несколько других приемов, которые не требуют болезненного сопоставления объектов и пакетов для правильной обработки завершения работы.
2. Да, вы это сделали, и я должным образом защищал ваш пост всеми способами, за исключением одного из ваших более поздних комментариев, который гласил: «Это, по крайней мере, позволяет вам сохранять ваши объекты в памяти в течение 99% времени вашего приложения». Я даже поддержал ваш ответ, поскольку мой — это просто разработка вашего. Поиск хитростей для хранения объектов в памяти — это то, что делают многие разработчики, и это может нанести ущерб Android. Если я неправильно воспринял этот комментарий, я приношу свои извинения и отредактирую соответствующим образом, но вы могли бы рассмотреть возможность конкретизации этой части, чтобы другие не восприняли это так, как я.
3. Хорошо, я думаю, я понимаю, как это может быть воспринято неправильно. Я постараюсь лучше разъяснить свою точку зрения о том, почему наличие стабильного места для размещения ваших объектов помогает улучшить ваше приложение.
Ответ №2:
Я предпочитаю подкласс Application и указывать на это в своем манифесте. Я думаю, что это разумный способ кодирования Android, хотя архитекторы Android из Google считают, что для этого следует использовать синглтоны (eek). Синглтоны имеют тот же срок службы, что и приложение, поэтому все, что к ним относится, относится и к приложению, за исключением гораздо меньшего количества зависимостей, создаваемых синглетами. По сути, они даже не используют пакеты. Я думаю, что использование подкласса Application значительно ускорило программирование на Android с гораздо меньшим количеством хлопот.
Теперь о недостатках. Ваше приложение может быть отключено, если телефону потребуется больше памяти или ваше приложение перейдет в фоновый режим. Это может означать, что пользователь ответил на звонок или проверил свою электронную почту. Так, например, скажем, у вас есть действие, которое заставляет пользователя входить в систему, чтобы получить токен, который другие действия будут использовать для выполнения вызовов сервера. Это то, что вы можете сохранить в своем объекте service (не Android service, а просто класс, который отправляет сетевые вызовы на ваш сервер), который вы храните в своем подклассе Application. Ну, если ваше приложение завершит работу, вы потеряете этот токен, и когда пользователь нажимает кнопку «Назад», ваш пользователь может вернуться к действию, предполагающему, что вы уже прошли проверку подлинности, и ваш класс обслуживания не работает.
Итак, что вы можете сделать? Продолжайте использовать ужасность пакета? Ну, нет, вы могли бы легко хранить токены безопасности в пакете (хотя могут возникнуть некоторые проблемы с безопасностью, в зависимости от того, как это работает для вашего приложения), или вам нужно кодировать свои действия, чтобы не предполагать определенное состояние, в котором находится приложение. Мне пришлось проверить потерю токена и перенаправить пользователя обратно на экран входа в систему, когда это произойдет. Но, в зависимости от того, в каком состоянии находится ваш объект приложения, это может быть сложно. Но имейте в виду, что ваше приложение может знать, когда оно завершается, и сохранять его внутреннее состояние в пакете. Это, по крайней мере, позволяет вам сохранять ваши объекты в памяти в течение 99% времени вашего приложения и сохранять / восстанавливать только при его завершении, а не постоянно сериализовать и десериализовать с помощью кода boiler plate всякий раз, когда вы переключаетесь между действиями. Использование приложения позволяет централизовать запуск и завершение работы вашей программы, а поскольку оно обычно живет дольше, чем любое другое действие, это может уменьшить потребность в программе для восстановления вашего приложения, когда пользователь переходит между действиями. Это делает ваш код более чистым, удаляя детали приложения из каждого действия, снижает накладные расходы, если ваше приложение уже создано, использует общие экземпляры / код и позволяет восстанавливать действия без потери всей вашей программы. Всем хорошим программам нужен централизованный концентратор, который является ядром, и подкласс Application дает вам это, позволяя вам участвовать в жизненном цикле Android.
Мой личный фаворит — использовать http://flexjson.sourceforge.net / для сериализации моих объектов Java в пакеты в формате JSON, если мне нужно отправить объекты или сохранить их. Намного проще, чем запись в sqlite DB, когда все, что вам нужно сделать, это сохранить данные. И приятно при отправке данных между двумя действиями с использованием объектов вместо разбитых примитивов.
Помните, что централизуя свою модель в приложении, вы создаете место для совместного использования кода между несколькими действиями, поэтому вы всегда можете делегировать сохранение Activities объекту в приложении, подключив onPause(), а также позволяя размещать сохранение в центре.
Комментарии:
1. Проблема с сериализацией сложных объектов заключается в том, что … это действие должно выполняться в основном потоке (при вызове saveInstanceState). Я полагаю, вы могли бы использовать AsyncTask для создания строки JSON, а затем запустить новое намерение, когда это будет сделано (для случая, когда вы начинаете новое действие). Я просто беспокоюсь о том, чтобы выполнять слишком много операций запуска / завершения работы в основном потоке.
2. Вы всегда можете отправить его в другой поток, но большинство объектов, которые вы отправляете, занимают всего 1-10 мс. Конечно, если вам нужно много сэкономить, вам нужно взвесить это, но даже большие списки и сложные объекты выполняются безумно быстро. Измеряйте, измеряйте, измеряйте со всеми задачами.
3. Хотя вы можете перенести его в другой поток, вы не можете выйти из этого метода и ожидать, что асинхронный поток не умрет. Поэтому вам нужно выполнить wait() в потоке, тогда в чем разница, если вы блокируете основной поток или выполняете фактическую работу над ним? Это один из тех же или значительно меньших потоков, если вы просто делаете это в основном потоке.
Ответ №3:
Короткий ответ: используйте пакеты, поскольку это упрощает сохранение вашего состояния, когда вы находитесь в фоновом режиме. Кроме того, это сложно.
Длинный ответ:
Насколько я понимаю, как только вызывается метод onPause вашей активности (и onSaveInstanceState, который дает вам пакет, в который вы должны хранить данные своей активности), ваш процесс может быть завершен без дальнейшего предупреждения. Позже, когда пользователь возвращается к вашему приложению, вашей активности присваивается вызов onCreate с этим исходным пакетом, из которого можно восстановить его состояние. Это произойдет со всеми вашими действиями в том, что было вашим исходным стеком.
Возможность восстановить ваше состояние из пакета (который Android сохранит для вас, когда ваш процесс завершится) — это то, как Android поддерживает миф о многозадачности. Если вы не сбрасываете состояние своей активности в пакет каждый раз при вызове onSaveInstanceState, ваше приложение будет выглядеть так, как будто оно было перезапущено, когда пользователь, возможно, просто отключился на секунду. Это может быть особенно тревожно, когда система ограничена в ресурсах, поскольку системе потребуется чаще отключать процессы, чтобы поддерживать быструю работу устройства
Почему приложение может быть плохим
Приложение фактически не получает возможности сохранить какие-либо свои данные, если процесс завершен. У него есть метод onDestroy, но в документах будет указано, что на самом деле это никогда не вызывается системой на реальном устройстве. Это означает, что в ограниченном случае, о котором я упоминал выше, любая случайная информация о том, что происходит в рамках действия (если вы сохранили ее в приложении), будет потеряна, если процесс будет завершен.
Разработчики часто упускают этот случай (и это может быть действительно раздражающим для пользователей), потому что они либо работают на телефоне разработчика, который никогда не сталкивается с одновременным использованием многих приложений. Мы также никогда не используем приложение какое-то время, затем переключаемся на другое приложение и через некоторое время переключаемся обратно.
Комментарии:
1. onDestroy() может вызываться без onPause() когда-либо вызывается. Например, если вызывается функция finish() , она может сделать это без вызова onPause(), в зависимости от того, как и когда она вызывается. Вероятность того, что это повлияет на ваш код, равна нулю, так как часто функция finish() выполняется действием, когда пользователь или приложение все равно выполняют свою задачу. При этом все это тоже отличные моменты.
2. Верно, бывают случаи, когда onPause не вызывается, но в этот момент вам не нужно заботиться о кэшировании ваших данных (поскольку активность удаляется, а не скрывается)
3. Честно говоря, это зависит от реализации программиста. Хотя я лично согласен с вами, у некоторых разработчиков могут быть особые потребности, поэтому необходимо добавить заявление.