Android: статическая переменная null на низкой памяти
У меня есть приложение, которое имеет некоторые статические переменные.
Эти переменные хранятся в независимом классе с именем DataContext.
Эти переменные инициализируются из необработанных файлов при запуске приложения (метод DataContext.initConstant() вызывается в onCreate() MyApplication, который расширяет Application).
(EDIT: метод initConstant использует AsyncTask для загрузки этих данных из файлов).
Когда мое приложение приходит на задний план в течение определенного времени или когда мое приложение используется для большой памяти, эти статические переменные становятся нулевыми.
-
Как это можно предотвратить?
-
Если не то, что я должен делать с моими статическими переменными?
У меня есть другие данные, которые хранятся в статических переменных, которые будут использоваться в разных действиях, но я их очищаю или передаю в null в onLowMemory()
MyApplication.
-
Каков наилучший способ хранения некоторых данных между действиями, если эти данные слишком велики для сериализации в Intent, база данных не может использоваться (по какой-либо причине) и не может быть сохранена в файлах с помощью сериализации?
Ответы
Ответ 1
Скорее всего, проблема в том, что ваше приложение убивается, когда оно находится в фоновом режиме, а затем воссоздается, когда вы возвращаетесь к нему. Ознакомьтесь с документацией Activity Lifecycle, когда это может произойти для одного действия. Вы должны убедиться, что вы перемещаете все, что хранится в памяти, в более постоянное хранилище в нужный момент времени, чтобы не потерять эту информацию, если приложение будет убито.
Я не уверен, что именно вы храните, но похоже, что использование общих настроек может работать хорошо. На этой странице Хранилище данных объясняется ряд различных способов более длительного хранения данных, включая Общие предпочтения.
Ответ 2
-
Вы не можете. Android должен время от времени освобождать память. Представьте себе, если бы все приложения имели массу статических данных, которые, как предполагается, постоянно проживали, - как вы поместили бы это в память? Это мобильный телефон. У него нет виртуальной памяти.
-
(и 3): все, что должно быть постоянным, должно храниться либо через SharedPreferences, либо в базе данных Sqlite, либо в файле.
Ответ 3
Если вы не использовали необработанные файлы, я бы посоветовал инициализировать, когда класс загружен.
Например,
public static Map<?,?> myStaticMap = new HashMap<?,?>();
static { //fill myStaticMap }
У вас есть некоторые проблемы, беспокоиться о том, что вы загружаете файлы таким образом. Например, как насчет ошибок ввода-вывода или проблем с задержкой? Вы получите предупреждения в пряниках (если вы их включите) для ввода/вывода в основной теме. Возможно, у вас должен быть объект для извлечения этих значений вместо класса со статическими полями. (возможно, со статическим кешем, хотя вы должны синхронизировать его перед проверкой/изменением)
Ответ 4
Я предполагаю, что это проблема кэширования данных.
Сохранение данных в статическом классе не гарантируется, когда пользователь часто меняет приложения. Система Android будет восстанавливать любые фоновые активности, когда память низкая. Статический класс определенно относится к этой категории.
Правильный способ сделать это - использовать sharedPreference для сохранения данных кеша.
Вы можете создать свой собственный getter и setter данных, которые вы хотите, и обернуть их вокруг объекта sharedPreference. Когда вы получаете доступ с помощью геттера, вы всегда должны проверить, пустое или недействительное значение. Вы можете сохранить update_time
при использовании setter.
Для данных, относящихся к конкретным действиям, вы можете просто использовать getPreference(permission)
, если вы хотите обмениваться данными между действиями и другими компонентами приложений, вы можете использовать getSharedPreference(name, permission)
.
Обычно разрешение будет MODE_PRIVATE таким образом, что данные могут быть доступны только в вашем приложении.
Вы должны сгруппировать данные и сохранить в свойстве sharedPreference. Это хорошая практика, потому что, когда вы хотите сделать недействительной эту группу данных, это всего лишь вопрос одного лайнера.
editor.clear(); editor.commit()
Если вы хотите кэшировать сложный объект, вы должны его сериализовать. Я предпочитаю формат JSON. Поэтому вам нужен механизм преобразования. Для этого я создам класс объектов данных, расширяющий класс JSONable. Класс JSONable будет иметь метод toJSON()
и readFromJSON()
. Это удобно при восстановлении и сериализации данных.
Ответ 5
Я храню объект User
и объект Client
в своей статической области. Я заметил, что время от времени ссылка становится нулевой. Итак, теперь в моих getters я проверяю, является ли это значение нулевым, и если это так, я перезапускаю приложение.
Intent i = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(i);
Я также мог бы перезагрузить клиента, потому что я храню токен доступа в prefs, но я делаю так много инициализации, что решил, что перезапуск приложения будет наилучшей идеей.
Ответ 6
В вашем методе onResume()
вы можете запросить статические данные, чтобы увидеть, присутствует ли он, а если нет, загрузите его снова.
Ответ 7
Вместо использования статической переменной u можно использовать общую настройку для сохранения значения.
Примечание: для общих предпочтений вы также не должны давать большую нагрузку.
Я решил эту проблему, имея суперкласс с функцией getter и setter для хранения и извлечения общей переменной предпочтения.
Весь класс в моем приложении расширил суперкласс вместо активности.