Использование класса приложения Android для сохранения данных

112

Я работаю над довольно сложным Android-приложением, для которого требуется довольно большой объем данных о приложении (я бы сказал, всего около 500 КБ - это много для мобильного устройства?). Насколько я могу судить, любое изменение ориентации в приложении (а точнее в деятельности) приводит к полному разрушению и воссозданию активности. Основываясь на моих выводах, класс Application не имеет того же жизненного цикла (т.е. он для всех намерений и целей всегда создается). Имеет ли смысл хранить информацию о состоянии внутри класса приложения, а затем ссылаться на нее из Activity, или это вообще не «приемлемый» метод из-за ограничений памяти на мобильных устройствах? Я очень ценю любые советы по этой теме. Спасибо!

Дэйв
источник
8
Просто имейте в виду, что данные в вашем приложении все равно могут быть удалены, если ваше приложение переходит в фоновый режим, поэтому это не решение для сохранения данных, которые вы всегда хотите вернуть. Это просто способ избавиться от необходимости часто воссоздавать дорогие объекты.
Шерил Саймон
2
Майра; Я не думаю, что приложение «обычно» удаляется (хотя, как кто-то указывает позже в этой теме, это «может» быть). Я, вероятно, собираюсь использовать какой-то «гибридный» подход к использованию приложения для хранения и загрузки данных, но затем использую атрибут «android: Ориентация» для действия в файле манифеста, чтобы переопределить нормальное поведение разрушение и восстановление деятельности. Все это, конечно, предполагает, что приложение может определить, «когда» оно уничтожается, чтобы данные могли быть сохранены.
Дэйв,

Ответы:

134

Не думаю, что 500 КБ - это такая уж большая проблема.

То, что вы описали, - это именно то, как я решил проблему потери данных в процессе работы. Я создал глобальный синглтон в классе Application и смог получить к нему доступ из использованных мной действий.

Вы можете передавать данные в глобальном синглтоне, если он будет использоваться много раз.

public class YourApplication extends Application 
{     
     public SomeDataClass data = new SomeDataClass();
}

Затем вызывайте его в любом действии:

YourApplication appState = ((YourApplication)this.getApplication());
appState.data.UseAGetterOrSetterHere(); // Do whatever you need to with the data here.

Я обсуждаю это здесь, в своем блоге , в разделе «Global Singleton».

Брайан Денни
источник
1
К сожалению, данная запись в блоге больше недоступна по этому адресу.
mikebabcock
1
Я перемещал вещи на своем сайте. Пока он не будет исправлен, вы можете найти его на archive.org здесь: web.archive.org/web/20130818035631/http://www.bryandenny.com/…
Брайан Денни
1
Я знаю, что это старый пост, но я только что столкнулся с проблемой, которую это могло решить, однако этот класс нужно как-то объявить в манифесте, нет? Я не могу посещать занятия, поэтому чувствую, что это то, чего мне не хватает ...
Зив Кестен
1
@ZivKesten Как насчет добавления атрибута name = в тег приложения внутри манифеста?
MikeC
@mgc, спасибо, прошло какое-то время, и да, именно так я в конечном итоге решил это, также я создал экземпляры этого класса везде, где мне было нужно, предоставив ему getApplicationContext () с приведением к этому классу
Зив Кестен
57

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

При необходимости ОС может убивать процессы. Все процессы разделены на 5 уровней «убиваемости», указанных в документе .

Так, например, если ваше приложение переходит в фоновый режим из-за того, что пользователь отвечает на входящий вызов, тогда в зависимости от состояния ОЗУ ОС может (или не может) убить ваш процесс (уничтожить Applicationэкземпляр в процессе) .

Я думаю, что лучшим подходом было бы сохранить ваши данные во внутреннем хранилище, а затем прочитать его, когда ваша деятельность возобновится.

ОБНОВИТЬ:

Получил много отрицательных отзывов, пора добавить уточнение. :) Ну, изначально я действительно использовал неправильное предположение, что состояние действительно важно для приложения. Однако, если ваше приложение в порядке, что иногда состояние теряется (это могут быть некоторые изображения, которые будут просто перечитаны / повторно загружены), тогда вполне нормально оставить его в качестве члена Application.

Вит Худенко
источник
14
Если приложение убито, кого это волнует, правда? Приложение ушло. Насколько я понимаю, Android будет восстанавливать процессы, которые содержат память, например Activity. Если процесс, содержащий приложение, будет убит (если Android вообще сделает это?), Это, по сути, похоже на убийство приложения. Пользователю нужно будет снова запустить приложение, и кого это волнует? Это новый экземпляр приложения.
Эндрю
14
Это стало неприятным сюрпризом для нас в продакшене. Поверьте, Android убивает процессы, это просто зависит от состояния RAM и других факторов, описанных в документации. Для нас это был кошмар, поэтому я просто делюсь своим реальным опытом. Ну, у нас этого не было в эмуляторах, но в реальном мире некоторые устройства «перегружены» приложениями, поэтому отключение фонового процесса - нормальная ситуация. Да, если пользователь затем решает вывести приложение на передний план - ОС восстанавливает свой стек, включая Applicationэкземпляр, однако статических данных, на которые вы рассчитываете, не будет, если вы не сохраните их.
Вит Худенко
2
Думаю, я, вероятно, буду использовать гибридный подход. Я уже знал о манифестном трюке, позволяющем отменить изменение ориентации (которое имеет другие преимущества). Поскольку приложение является игрой, я не уверен, что сохранение данных между запусками достаточно «важно»; хотя, вероятно, это будет не так уж сложно, так как большинство данных можно сериализовать (хотя я бы не хотел сериализовать и десериализовать между каждым изменением ориентации). Я определенно ценю вклад. Я бы не сказал, что те, которые зависят от экземпляра приложения, «неправильны». Многое зависит от приложения :).
Дэйв
1
@Arhimed, вы слишком обобщаете свой ответ. И предлагая узкий подход, основанный на вашем предположении. Ложное предположение: данные, хранящиеся в статических переменных, должны сохраняться во всех сеансах приложения. Может быть множество случаев использования, когда данные тривиальны и не требуют немедленного сохранения.
Mandar Limaye
2
У меня около 1 МБ данных со сложной структурой. Сериализация / десериализация может стоить мне до 2-3 секунд, когда устройство перегружено работой. Идея сохранять / загружать между занятиями занимает слишком много времени. Использую приложение как хранилище. Конечно, мой класс данных, хранящийся в экземпляре приложения, проверяется каждым методом - данные все еще живы или должны быть загружены. Итак, Дэйв должен: 1. обеспечить загрузку / сохранение функций 2. сохранить данные в приложении. 3. Логика тройной проверки доступа к данным.
Костадин
6

Если вы хотите получить доступ к «Глобальному синглтону» вне действия и не хотите проходить Contextчерез все задействованные объекты для получения синглтона, вы можете просто определить статический атрибут в своем классе приложения, который содержит ссылку на сам. Просто инициализируйте атрибут в onCreate()методе.

Например:

public class ApplicationController extends Application {
    private static ApplicationController _appCtrl;

    public static ApplicationController getAppCtrl()
    {
         return _appCtrl;
    }
}

Поскольку подклассы Applicationтакже могут получать ресурсы, вы можете получить к ним доступ просто, когда определите статический метод, который их возвращает, например:

public static Resources getAppResources()
{
    return _appCtrl.getResources();
}

Но будьте очень осторожны при передаче контекстных ссылок, чтобы избежать утечки памяти .

саксофоны
источник
6
Вы забыли отметить, что для создания экземпляра класса необходимо добавить атрибут android: name = ". ApplicationController" xml тег приложения в манифест.
eggie5
На самом деле вам не нужно расширять, Applicationчтобы сделать это. Для этого вы можете объявить статическую переменную-член в любом классе .
Дэвид Вассер
2

Дэйв, что это за данные? Если это общие данные, относящиеся к приложению в целом (пример: пользовательские данные), расширьте класс Application и сохраните его там. Если данные относятся к Activity, следует использовать обработчики onSaveInstanceState и onRestoreInstanceState для сохранения данных при повороте экрана.

Андрей
источник
Что, если данные действительно большие для хранения в посылке? Вот что я получаю: android.os.TransactionTooLargeException: размер пакета данных 838396 байт
Арджун Иссар
1

Фактически вы можете переопределить функцию ориентации, чтобы убедиться, что ваша деятельность не уничтожена и не воссоздана. Смотри сюда .

Grantland Chew
источник
16
Вы можете многое сделать. Это не значит, что это хорошие идеи. Это плохая идея.
Эндрю
Тестирование путем изменения ориентации экрана - это самый простой способ убедиться, что ваше приложение выполняет то, что предполагает Android.
18446744073709551615
0

Вы можете создать класс Application и сохранить все свои данные на нем для использования в любом месте вашего приложения.

Ашиш Джайсвал
источник
0

Я знаю, что это очень старый вопрос, но использование ViewModel из компонентов Jetpack - лучший способ сохранить данные между ротацией Activity.

Класс ViewModel разработан для хранения данных, связанных с пользовательским интерфейсом, и управления ими с учетом жизненного цикла. Класс ViewModel позволяет данным сохраняться при изменении конфигурации, например, при повороте экрана.

Dharmendra
источник