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 датотеку у RAM меморију и парсира је у 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 (застарео) 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-а. Ово омогућава избегавање цурења меморије повезаних са заборављеним слушаоцима. У старијим верзијама, програмер је дужан да ручно позове 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-у. При наредним покретањима апликације, тема се обнавља из сачуваних подешавања. За реактивно ажурирање интерфејса користи се посматрање промена кроз 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) на контексту. Чишћење података апликације кроз Подешавања → Апликације → Обриши податке такође уклања све SharedPreferences датотеке.
За нове пројекте Google препоручује DataStore као замену за SharedPreferences. DataStore обезбеђује асинхрони рад са корутинама, типску безбедност (Proto DataStore) и аутоматске миграције. SharedPreferences треба изабрати само за пројекте са минималном верзијом испод API 14 или када је потребна брза интеграција без додатних зависности.
За шифровање података користите EncryptedSharedPreferences из AndroidX Security библиотеке. Она аутоматски шифрује кључеве и вредности помоћу AES-256 GCM. Процес подешавања је минималан: getSharedPreferences се замењује са EncryptedSharedPreferences.create уз навођење главног кључа из Android Keystore-а.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође