Лучшие решения для Android SharedPreferences

В приложении, которое я создаю, мы немного полагаемся на SharedPreferences, это заставило меня задуматься о том, что лучше всего подходит для доступа к SharedPreferences. Например, многие люди говорят, что подходящий способ получить доступ к нему осуществляется через этот вызов:

PreferenceManager.getDefaultSharedPreferences(Context context) 

Однако, похоже, это может быть опасно. Если у вас большое приложение, основанное на SharedPreferences, у вас может быть ключевое дублирование, особенно в случае использования библиотеки сторонних разработчиков, которая также использует SharedPreferences. Мне кажется, что лучший призыв к использованию:

 Context.getSharedPreferences(String name, int mode) 

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

Также на основе этого вопроса SO: должен ли быть доступ к SharedPreferences из потока пользовательского интерфейса? , Кажется, что доступ к SharedPreferences должен выполняться из потока пользовательского интерфейса, что имеет смысл.

Есть ли другие рекомендации, которые разработчики Android должны знать при использовании SharedPreferences в своих приложениях?

Solutions Collecting From Web of "Лучшие решения для Android SharedPreferences"

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

Библиотеки не должны использовать эту конкретную SharedPreferences . Стандартные SharedPreferences должны использоваться только приложением.

Таким образом, если у вас есть класс, который сильно зависит от SharedPreferences, вы можете создать файл предпочтений, который используется только вашим классом.

Вы, безусловно, можете это сделать. На уровне приложения я бы не стал основной причиной для SharedPreferences , чтобы они были распределены между компонентами приложения. У команды разработчиков не должно быть проблем с управлением этим пространством имен, так же как у них не должно быть проблем с управлением именами классов, пакетов, ресурсов или другого материала на уровне проекта. Кроме того, по умолчанию SharedPreferences использует вашу PreferenceActivity .

Однако, возвращаясь к вашим точкам библиотек, библиотеки многократного использования должны использовать отдельные SharedPreferences для своей библиотеки. Я бы не основывал его на имени класса, потому что тогда вы один рефакторинг от взлома приложения. Вместо этого выберите уникальное имя (например, на основе имени библиотеки, например "com.commonsware.cwac.wakeful.WakefulIntentService" ), но стабильного.

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

В идеале, да. Недавно я выпустил SharedPreferencesLoader который помогает с этим.

Есть ли другие рекомендации, которые разработчики Android должны знать при использовании SharedPreferences в своих приложениях?

Не переусердствуйте на них. Они хранятся в файлах XML и не являются транзакционными. База данных должна быть вашим основным хранилищем данных, особенно для данных, которые вы действительно не хотите потерять.

Я написал небольшую статью, которая также может быть найдена здесь . Он описывает, что SharedPreferences :

Лучшая практика: SharedPreferences

Android предоставляет множество способов хранения данных приложения. Один из этих способов приводит нас к объекту SharedPreferences, который используется для хранения частных примитивных данных в парах ключ-значение.

Вся логика основана только на трех простых классах:

  • SharedPreferences
  • SharedPreferences.Editor
  • SharedPreferences.OnSharedPreferenceChangeListener

SharedPreferences

Основными из них являются SharedPreferences . Он отвечает за получение (разбор) хранимых данных, предоставляет интерфейс для получения объекта Editor и интерфейсов для добавления и удаления OnSharedPreferenceChangeListener

  • Для создания SharedPreferences вам понадобится объект Context (может быть Context приложения)
  • Метод getSharedPreferences анализирует файл предпочтений и создает для него объект Map
  • Вы можете создать его в нескольких режимах, предоставляемых Context, настоятельно рекомендуется использовать MODE_PRIVATE, потому что создание общедоступных для чтения / записываемых файлов очень опасно и может привести к появлению ошибок в приложениях

     // parse Preference file SharedPreferences preferences = context.getSharedPreferences("com.example.app", Context.MODE_PRIVATE); // get values from Map preferences.getBoolean("key", defaultValue) preferences.get..("key", defaultValue) // you can get all Map but be careful you must not modify the collection returned by this // method, or alter any of its contents. Map<String, ?> all = preferences.getAll(); // get Editor object SharedPreferences.Editor editor = preferences.edit(); //add on Change Listener preferences.registerOnSharedPreferenceChangeListener(mListener); //remove on Change Listener preferences.unregisterOnSharedPreferenceChangeListener(mListener); // listener example SharedPreferences.OnSharedPreferenceChangeListener mOnSharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { } }; 

редактор

SharedPreferences.Editor – это интерфейс, используемый для изменения значений в объекте SharedPreferences . Все изменения, внесенные в редактор, переносятся и не копируются обратно в исходные SharedPreferences до SharedPreferences пор, пока вы не назовете commit () или apply ()

  • Используйте простой интерфейс для размещения значений в Editor
  • Сохранять значения, синхронные с commit() или асинхронные, с apply которое выполняется быстрее. Фактически использование разных потоков с использованием commit() безопаснее. Вот почему я предпочитаю использовать commit() .
  • Удалите одно значение с помощью remove() или очистите все значения с помощью clear()

     // get Editor object SharedPreferences.Editor editor = preferences.edit(); // put values in editor editor.putBoolean("key", value); editor.put..("key", value); // remove single value by key editor.remove("key"); // remove all values editor.clear(); // commit your putted values to the SharedPreferences object synchronously // returns true if success boolean result = editor.commit(); // do the same as commit() but asynchronously (faster but not safely) // returns nothing editor.apply(); 

Производительность и советы

  • SharedPreferences – это объект Singleton, поэтому вы можете легко получить столько ссылок, сколько хотите, он открывает файл только при первом вызове getSharedPreferences или создает для него только одну ссылку.

     // There are 1000 String values in preferences SharedPreferences first = context.getSharedPreferences("com.example.app", Context.MODE_PRIVATE); // call time = 4 milliseconds SharedPreferences second = context.getSharedPreferences("com.example.app", Context.MODE_PRIVATE); // call time = 0 milliseconds SharedPreferences third = context.getSharedPreferences("com.example.app", Context.MODE_PRIVATE); // call time = 0 milliseconds 
  • Поскольку SharedPreferences – это объект Singleton, вы можете изменить любой из его экземпляров и не бояться, что их данные будут разными

     first.edit().putInt("key",15).commit(); int firstValue = first.getInt("key",0)); // firstValue is 15 int secondValue = second.getInt("key",0)); // secondValue is also 15 
  • Когда вы вызываете метод get впервые, он анализирует значение по ключу и добавляет это значение к карте. Поэтому для второго вызова он просто получает его с карты, без разбора.

     first.getString("key", null) // call time = 147 milliseconds first.getString("key", null) // call time = 0 milliseconds second.getString("key", null) // call time = 0 milliseconds third.getString("key", null) // call time = 0 milliseconds 
  • Помните, что чем больше объект Preference, тем дольше будут выполняться операции get , commit , apply , remove и clear . Поэтому настоятельно рекомендуется разделить ваши данные на разных небольших объектах.

  • Ваши настройки не будут удалены после обновления приложения. Таким образом, есть случаи, когда вам нужно создать некоторую схему миграции. Например, у вас есть приложение, которое анализирует локальный JSON в начале приложения, для этого только после первого запуска вы решили сохранить логический флаг wasLocalDataLoaded . Через некоторое время вы обновили JSON и выпустили новую версию приложения. Пользователи будут обновлять свои приложения, но они не будут загружать новый JSON, потому что они уже сделали это в первой версии приложения.

     public class MigrationManager { private final static String KEY_PREFERENCES_VERSION = "key_preferences_version"; private final static int PREFERENCES_VERSION = 2; public static void migrate(Context context) { SharedPreferences preferences = context.getSharedPreferences("pref", Context.MODE_PRIVATE); checkPreferences(preferences); } private static void checkPreferences(SharedPreferences thePreferences) { final double oldVersion = thePreferences.getInt(KEY_PREFERENCES_VERSION, 1); if (oldVersion < PREFERENCES_VERSION) { final SharedPreferences.Editor edit = thePreferences.edit(); edit.clear(); edit.putInt(KEY_PREFERENCES_VERSION, currentVersion); edit.commit(); } } } 
  • SharedPreferences хранятся в XML-файле в папке с данными приложения

     // yours preferences /data/data/YOUR_PACKAGE_NAME/shared_prefs/YOUR_PREFS_NAME.xml // default preferences /data/data/YOUR_PACKAGE_NAME/shared_prefs/YOUR_PACKAGE_NAME_preferences.xml 

Руководство для Android.

Образец кода

 public class PreferencesManager { private static final String PREF_NAME = "com.example.app.PREF_NAME"; private static final String KEY_VALUE = "com.example.app.KEY_VALUE"; private static PreferencesManager sInstance; private final SharedPreferences mPref; private PreferencesManager(Context context) { mPref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); } public static synchronized void initializeInstance(Context context) { if (sInstance == null) { sInstance = new PreferencesManager(context); } } public static synchronized PreferencesManager getInstance() { if (sInstance == null) { throw new IllegalStateException(PreferencesManager.class.getSimpleName() + " is not initialized, call initializeInstance(..) method first."); } return sInstance; } public void setValue(long value) { mPref.edit() .putLong(KEY_VALUE, value) .commit(); } public long getValue() { return mPref.getLong(KEY_VALUE, 0); } public void remove(String key) { mPref.edit() .remove(key) .commit(); } public boolean clear() { return mPref.edit() .clear() .commit(); } } 

Существует несколько библиотек, которые помогут вам справиться с SharedPreferences. Недавно я обнаружил Hawk ( https://github.com/orhanobut/hawk ) и StoreBox ( https://github.com/martino2k6/StoreBox ).

Это мой путь

Для записи

 SharedPreferences settings = context.getSharedPreferences("prefs", 0); SharedPreferences.Editor editore = settings.edit(); editore.putString("key", "some value"); editore.apply(); 

читать

 SharedPreferences settings = getSharedPreferences("prefs", 0); Strings value = settings.getString("key", "");