SharedPreferences — это ключ-значение хранилище данных на Android, предназначенное для сохранения простых настроек и конфигураций приложения. Данные хранятся в XML-файле на устройстве и доступны только внутри приложения, которое их создало. Согласно официальной документации Android Developers, 2025, SharedPreferences поддерживает хранение примитивных типов: String, Int, Boolean, Float, Long и Set<String>. Это самое простое и быстрое решение для сохранения небольших объёмов пользовательских настроек без необходимости в SQL-запросах или работе с файловой системой напрямую.
Главное
SharedPreferences — это встроенный механизм Android для хранения пар ключ-значение в XML-файле на внутреннем хранилище устройства. Он доступен начиная с API Level 1 и не требует подключения дополнительных библиотек. Основное назначение — сохранение пользовательских настроек, состояния интерфейса, флагов first-launch и других простых данных, которые не требуют структурированной базы данных.
Каждый файл SharedPreferences связан с конкретным именем и режимом доступа. По умолчанию используется режим Context.MODE_PRIVATE, который ограничивает доступ к файлу только текущим приложением. Ранее Android поддерживал режимы MODE_WORLD_READABLE и MODE_WORLD_WRITEABLE, но они были объявлены устаревшими начиная с API Level 17 и полностью удалены в Android 7.0 (API 24) из соображений безопасности.
Несмотря на свою простоту, SharedPreferences используется в миллионах Android-приложений. По данным Google, более 90% приложений, опубликованных в Google Play, используют SharedPreferences для хранения настроек. Однако для сложных сценариев (большие объёмы данных, типобезопасность, асинхронность) Google рекомендует более современные решения, такие как Preferences DataStore из библиотеки Android Jetpack.
Физически SharedPreferences хранится в виде XML-файла в директории приложения: /data/data/{package_name}/shared_prefs/{file_name}.xml. Файл содержит корневой элемент <map> с дочерними элементами <string>, <int>, <boolean>, <float> и <long> в зависимости от типа сохранённого значения. Размер файла не ограничен, но для больших объёмов данных (более 100 KB) производительность чтения и записи начинает заметно снижаться.
Файлы SharedPreferences не шифруются по умолчанию. Данные хранятся в открытом виде в файловой системе устройства. Для хранения чувствительных данных (токены, пароли) рекомендуется использовать EncryptedSharedPreferences из библиотеки AndroidX Security, которая автоматически шифрует ключи и значения с помощью AES256-GCM.
SharedPreferences работает по принципу кэширования в памяти с периодической синхронизацией на диск. При первом обращении к файлу (через getSharedPreferences) Android загружает XML-файл в оперативную память и парсит его в объект Map. Все последующие операции чтения выполняются из памяти, без повторного чтения с диска. Это обеспечивает высокую скорость доступа к данным.
Операции записи используют Editor — внутренний буфер изменений. Когда разработчик вызывает putString или putBoolean, изменения сохраняются в объекте Editor в памяти. Фактическая запись на диск происходит при вызове метода commit (синхронно) или apply (асинхронно). До вызова этих методов данные не сохраняются, и при аварийном завершении приложения изменения могут быть потеряны.
Для получения экземпляра SharedPreferences используются два метода: getPreferences и getSharedPreferences. Первый доступен только внутри Activity и создаёт файл с именем Activity. Второй — более гибкий, принимает имя файла и режим доступа, и доступен из любого контекста (Application, Activity, Service). Рекомендуется использовать getSharedPreferences с именем файла, соответствующим модулю или функциональности приложения.
// Получение SharedPreferences
val prefs = context.getSharedPreferences(
"user_settings", Context.MODE_PRIVATE
)
// Запись данных
with(prefs.edit()) {
putString("username", "Анна")
putInt("age", 28)
putBoolean("isLoggedIn", true)
apply()
}
// Чтение данных
val username = prefs.getString("username", "")
val age = prefs.getInt("age", 0)
val isLoggedIn = prefs.getBoolean("isLoggedIn", false)
При использовании MODE_MULTI_PROCESS (deprecated) SharedPreferences синхронизируется между процессами. Однако эта синхронизация не гарантирует атомарность, и Google рекомендует избегать использования SharedPreferences в multi-process сценариях. Для таких случаев лучше использовать ContentProvider, Room с межпроцессным доступом или DataStore.
SharedPreferences предоставляет набор методов для чтения данных по ключу и интерфейс Editor для записи. Каждый метод чтения принимает два параметра: ключ и значение по умолчанию, которое возвращается, если ключ не найден. Значение по умолчанию определяет также тип возвращаемого значения: getString возвращает String, getInt — Int и так далее.
| Метод чтения | Метод записи | Тип данных |
|---|---|---|
| getString | putString | String |
| getInt | putInt | Int |
| getBoolean | putBoolean | Boolean |
| getFloat | putFloat | Float |
| getLong | putLong | Long |
| getStringSet | putStringSet | Set<String> |
Editor — это внутренний объект SharedPreferences, который собирает изменения в буфере. После внесения всех изменений разработчик вызывает commit() (синхронная запись) или apply() (асинхронная запись). Разница критична: commit блокирует текущий поток до полной записи на диск и возвращает boolean (успех/неудача), а apply выполняет запись в фоновом потоке и немедленно возвращает управление, но не возвращает результат.
Рекомендуется использовать apply вместо commit во всех случаях, когда не нужно знать результат записи. apply быстрее и не блокирует UI-поток. commit следует использовать только когда критично знать, успешно ли сохранились данные, или при работе с multi-process режимом. Для удаления отдельных ключей используется метод remove, для полной очистки — clear. Все операции удаления также выполняются через Editor.
// Множественные изменения - один apply
prefs.edit {
putString("theme", "dark")
putBoolean("notifications", false)
remove("old_key")
}
// Слушатель изменения значений
prefs.registerOnSharedPreferenceChangeListener { prefs, key ->
Log.d("TAG", "Изменился ключ: $key")
}
Начиная с Android 12 (API 31), SharedPreferences была дополнена поддержкой registerOnSharedPreferenceChangeListener с автоматической отпиской через Lifecycle. Это позволяет избежать утечек памяти, связанных с забытыми listener-ами. В более старых версиях разработчик обязан вручную вызывать unregisterOnSharedPreferenceChangeListener в onDestroy или onStop компонента.
Несмотря на широкую распространённость, SharedPreferences не является универсальным решением для всех сценариев хранения данных на Android. В зависимости от объёма данных, требований к типобезопасности и производительности, Google рекомендует различные альтернативы, включённые в Android Jetpack и стандартную библиотеку Android.
| Решение | Когда использовать | Недостатки |
|---|---|---|
| SharedPreferences | Небольшие настройки (до 100 ключей) | Нет типобезопасности, синхронное чтение |
| DataStore | Настройки средней сложности с корутинами | Нет обратной совместимости ниже API 14 |
| Room | Структурированные данные и списки | Избыточен для 3-5 настроек |
| EncryptedSharedPreferences | Чувствительные данные и токены | Зависимость от AndroidX Security |
DataStore — это библиотека Android Jetpack, представленная Google как замена SharedPreferences. Она предоставляет два варианта: Preferences DataStore (ключ-значение, как SharedPreferences) и Proto DataStore (типизированное хранение через Protocol Buffers). DataStore использует корутины и Flow для асинхронной работы, гарантирует типобезопасность и автоматически обрабатывает миграции версий. Google рекомендует DataStore для всех новых проектов.
Основное преимущество DataStore — асинхронность на уровне API. Все операции чтения возвращают Flow, а операции записи являются suspend-функциями. Это полностью исключает блокировку UI-потока, которая возможна при синхронном чтении SharedPreferences. Кроме того, DataStore гарантирует консистентность данных: запись выполняется в транзакции, и при сбое все изменения откатываются.
Рассмотрим практический пример: настройки темы оформления (светлая/тёмная/системная) в Android-приложении. Пользователь выбирает тему, и выбор сохраняется в SharedPreferences. При последующих запусках приложения тема восстанавливается из сохранённых настроек. Для реактивного обновления UI используется наблюдение за изменениями через SharedPreferences.OnSharedPreferenceChangeListener.
Создадим класс ThemePreferences, который инкапсулирует всю работу с SharedPreferences для темы. Класс предоставляет методы getTheme (чтение), setTheme (запись) и observeTheme (наблюдение). Имя файла настроек будет "app_preferences" с режимом MODE_PRIVATE. Для удобства ключи вынесены в companion object как константы.
class ThemePreferences(context: Context) {
companion object {
private const val PREF_NAME = "app_preferences"
private const val KEY_THEME = "theme_mode"
const val THEME_LIGHT = "light"
const val THEME_DARK = "dark"
const val THEME_SYSTEM = "system"
}
private val prefs = context
.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
fun getTheme(): String =
prefs.getString(KEY_THEME, THEME_SYSTEM) ?: THEME_SYSTEM
fun setTheme(theme: String) {
prefs.edit { putString(KEY_THEME, theme) }
}
fun observeTheme(callback: (String) -> Unit) {
prefs.registerOnSharedPreferenceChangeListener { _, key ->
if (key == KEY_THEME) {
callback.invoke(getTheme())
}
}
}
}
В Activity или Fragment получение экземпляра ThemePreferences выполняется через контекст приложения. При инициализации вызывается getTheme для установки актуальной темы. При выборе пользователем новой темы вызывается setTheme, и через observeTheme интерфейс обновляется без перезапуска Activity. Важно не забыть отписаться от listener в onDestroy для предотвращения утечки памяти, особенно если Activity пересоздаётся при изменении конфигурации.
Для приложений с минимальной целевой версией Android 12+ рекомендуется использовать registerOnSharedPreferenceChangeListener совместно с LifecycleObserver. Это автоматически управляет подпиской и отпиской при изменении жизненного цикла компонента. Для более старых версий подписку и отписку необходимо управлять вручную, что является частым источником ошибок в production-приложениях, использующих SharedPreferences.
Часто задаваемые вопросы
SharedPreferences напрямую поддерживает только примитивные типы и Set<String>. Для хранения объектов необходимо сериализовать их в JSON-строку через Gson или Moshi, сохранить через putString, и десериализовать при чтении. Для сложных объектов с большим количеством полей рекомендуется использовать Room вместо SharedPreferences с JSON-сериализацией.
Да, SharedPreferences thread-safe. Все операции чтения и записи синхронизированы на уровне объекта SharedPreferences и его Editor. Однако при использовании multi-process режима синхронизация не гарантируется. Для конкурентного доступа из нескольких потоков внутри одного приложения SharedPreferences безопасен без дополнительных блокировок.
Для полной очистки всех данных из SharedPreferences вызовите метод clear() на Editor и примените изменения через apply. Если нужно удалить сам XML-файл, используйте deleteSharedPreferences(name) на контексте. Очистка данных приложения через Settings → Приложения → Очистить данные также удаляет все файлы SharedPreferences.
Для новых проектов Google рекомендует DataStore как замену SharedPreferences. DataStore обеспечивает асинхронную работу с корутинами, типобезопасность (Proto DataStore) и автоматические миграции. SharedPreferences стоит выбирать только для проектов с минимальной версией ниже API 14 или при необходимости быстрой интеграции без дополнительных зависимостей.
Для шифрования данных используйте EncryptedSharedPreferences из библиотеки AndroidX Security. Она автоматически шифрует ключи и значения с помощью AES-256 GCM. Процесс настройки минимален: getSharedPreferences заменяется на EncryptedSharedPreferences.create с указанием master-ключа из Android Keystore.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также