DataStore: co to je, základy ukládání dat a náhrada SharedPreferences

Autor: IT Sectr Publikováno: 2026-03-12 Doba čtení: 9 min

DataStore — komponent z knihovny Jetpack určený pro ukládání malých objemů dat v Android aplikacích. Na rozdíl od SharedPreferences pracuje asynchronně a zaručuje konzistenci dat při konkurentním přístupu. Podle údajů Google, 2024 používá DataStore Kotlin Coroutines a Flow, což jej činí bezpečným pro hlavní vlákno a vhodným pro reaktivní architektury.

Hlavní body

  • DataStore — náhrada SharedPreferences s asynchronním API a datovými typy přes Protocol Buffers
  • Preferences DataStore — jednoduchý Key-Store se čtením přes Flow a transakcemi
  • Proto DataStore — typované úložiště s automatickými migracemi schématu
  • SharedPreferences — synchronní API blokující UI vlákno při velkých objemech
  • Migrace se provádí přes speciální rozhraní SharedPreferencesMigration bez ztráty dat

Co je DataStore?

DataStore — řešení od Google pro lokální ukládání dat v Android, představené v roce 2020 jako alternativa k SharedPreferences. Podporuje dva režimy: Preferences DataStore (jednoduché páry klíč-hodnota) a Proto DataStore (typované schéma založené na Protocol Buffers).

Hlavní výhoda — plná asynchronnost: všechny operace čtení vracejí Flow z Kotlin Coroutines a zápis se provádí v kontextu coroutine. To eliminuje blokování hlavního vlákna, které bylo typickým problémem SharedPreferences při práci s velkými objemy dat.

DataStore zaručuje atomicitu operací: konkurentní zápisy nevedou ke ztrátě dat díky transakčnímu modelu. Pokud dvě komponenty současně mění stejnou hodnotu, DataStore správně zpracuje konflikt pomocí mechanismu compare-and-swap.

Podle údajů Google I/O 2023 se DataStore používá ve 40 % nových projektů na Android a Google doporučuje migraci ze SharedPreferences ve všech aplikacích, kde je vyžadována stabilita ukládání nastavení.

Architektura DataStore

Základem DataStore je SingleProcessDataStore — implementace pracující v rámci jednoho procesu. Používá souborové úložiště se zámky na úrovni souboru: při zápisu dat je soubor uzamčen, což zabraňuje poškození při konkurentním přístupu.

DataStore automaticky zpracovává chyby deserializace: pokud je soubor poškozen, vrátí výchozí hodnotu a přepíše soubor. Toto chování se konfiguruje přes corruptionHandler, který lze nastavit při vytváření DataStore.

Problémy SharedPreferences, které DataStore řeší

SharedPreferences trpí třemi zásadními problémy: synchronní čtení z disku na hlavním vlákně, absence záruk atomity při konkurentních zápisech a nemožnost reaktivního sledování změn. DataStore řeší všechny tři: Flow pro pozorování, zámek souboru pro atomicitu a asynchronní API pro bezpečnost vláken.

Jak DataStore funguje v Android?

DataStore ukládá data do souborů ve vnitřní paměti zařízení. Preferences DataStore používá formát souboru podobný SharedPreferences, ale s dodatečnými metadaty pro kontrolu integrity. Proto DataStore používá binární formát Protocol Buffers, což zmenšuje velikost souboru a zrychluje serializaci.

Při čtení dat DataStore načte celý soubor do paměti jednorázově, poté odběratelé obdrží aktuální stav přes Flow. Změny jsou automaticky přenášeny všem aktivním odběratelům — není vyžadována ruční registrace listenerů, jako u SharedPreferences.

Princip fungování Preferences DataStore

Preferences DataStore používá vestavěný serializační mechanismus založený na Map. Každý záznam je pár řetězce a primitivního typu (Int, Boolean, Float, Long, String, Set). Data jsou uložena v XML souboru, podobně jako SharedPreferences, ale s atomickým zápisem přes zámek souboru.

Příklad vytvoření Preferences DataStore: rozšíření preferencesDataStore na Context vytvoří singleton s názvem souboru. Při opakovaných voláních se vrací stejná instance — to eliminuje duplikování souborů a záměnu s různými instancemi úložiště.

Princip fungování Proto DataStore

Proto DataStore vyžaduje definování datového schématu přes .proto soubor a kompilaci pomocí protobuf pluginu. Generovaná Java třída se používá jako jediný vstupní bod pro všechna pole — to eliminuje překlepy v klíčích, typické pro SharedPreferences.

Schéma Proto DataStore se definuje jednou a podporuje přidávání nových polí bez ztráty starých dat. Pokud se v nové verzi aplikace přidá pole s výchozí hodnotou, starý soubor bude správně deserializován — zpětná kompatibilita je zabudována do protokolu.

Preferences DataStore a Proto DataStore: srovnání

Výběr mezi Preferences DataStore a Proto DataStore závisí na složitosti dat a požadavcích na typování. Obě varianty jsou asynchronní a transakční, ale liší se úrovní type-safety a výkonem serializace.

VlastnostPreferences DataStoreProto DataStore
TypováníSlabé (klíč-hodnota)Silné (generovaná třída)
SerializaceXML (vestavěná)Protocol Buffers (protobuf)
Velikost souboruVelká (čitelné XML)Malá (binární)
SložitostNízká (bez .proto)Střední (vyžaduje .proto)
Migrace schématuŽádné schémaAutomatická (proto)
KompatibilitaSharedPreferences (přes migraci)Pouze Proto DataStore

Kdy zvolit Preferences DataStore

Preferences DataStore je vhodný pro jednoduchá nastavení: příznaky zapnutí funkcí, řetězec autorizačního tokenu, počet spuštění aplikace. Pokud je dat málo (do 10–15 klíčů) a nevyžadují přísné schéma — Preferences DataStore poskytuje minimální práh vstupu bez připojování protobuf pluginu.

Kdy zvolit Proto DataStore

Proto DataStore je opodstatněný, když je datová struktura složitá nebo se může měnit mezi verzemi aplikace. Například nastavení profilu uživatele nebo konfigurace A/B testů s 20+ poli. Protobuf poskytuje silné typování a automatické migrace, což eliminuje chyby za běhu kvůli neshodě klíčů.

Jak migrovat ze SharedPreferences na DataStore

Google poskytuje vestavěný mechanismus migrace přes třídu SharedPreferencesMigration. Migrace se provádí jednorázově při prvním spuštění po aktualizaci aplikace: DataStore načte data ze SharedPreferences, zapíše je do svého formátu a označí migraci jako dokončenou.

Migrace podporuje vlastní transformace: pokud se klíče v SharedPreferences neshodují s požadovanými klíči DataStore, lze definovat transformační funkci přes SharedPreferencesMigration. To umožňuje přejmenovávání klíčů a změnu datových typů v procesu migrace.

Migrace krok za krokem

Prvním krokem přidejte DataStore do build.gradle a vytvořte instanci DataStore s migrací: SharedPreferencesMigration přijímá název SharedPreferences souboru a sadu klíčů k přenesení. Druhým krokem odstraňte veškerý kód pracující přes SharedPreferences a nahraďte jej voláními DataStore. Třetím — otestujte migraci: při prvním spuštění by se data měla objevit v DataStore a starý SharedPreferences soubor by měl přestat být používán.

kotlin
val Context.dataStore by preferencesDataStore(
    name = "settings",
    produceMigrations = { context ->
        listOf(
            SharedPreferencesMigration(context, "old_prefs")
        )
    }
)

Příklady použití DataStore v kódu

DataStore se snadno integruje do existujícího projektu. Níže jsou uvedeny praktické příklady pro Preferences DataStore a Proto DataStore — oba demonstrují čtení, zápis a reaktivní pozorování dat.

Preferences DataStore: čtení a zápis nastavení

V tomto příkladu Preferences DataStore ukládá tři nastavení: tmavý motiv, uživatelské jméno a počet spuštění. Čtení se provádí přes rozšíření .data, které vrací Flow. Zápis — přes suspend funkci .edit, která zaručuje atomicitu změn.

kotlin
val Context.settingsDataStore by preferencesDataStore(name = "settings")

val isDarkMode: Flow<Boolean> = settingsDataStore.data
    .map { preferences ->
        preferences[booleanPreferencesKey("dark_mode")] ?: false
    }

suspend fun toggleDarkMode() {
    settingsDataStore.edit { prefs ->
        val current = prefs[booleanPreferencesKey("dark_mode")] ?: false
        prefs[booleanPreferencesKey("dark_mode")] = !current
    }
}

Proto DataStore: schéma a použití

Proto DataStore vyžaduje definici .proto souboru. Po kompilaci je vytvořena třída UserSettings, která se používá pro čtení a zápis. Migrace verzí schématu jsou popsány ve stejném .proto souboru a aplikovány automaticky.

kotlin
// user_preferences.proto
syntax = "proto3";

message UserPreferences {
    string display_name = 1;
    int32 notification_count = 2;
    bool notifications_enabled = 3;
}

// Čtení z DataStore
val userPreferencesFlow: Flow<UserPreferences> =
    protoDataStore.data

// Zápis nových hodnot
suspend fun updateDisplayName(name: String) {
    protoDataStore.updateData { prefs ->
        prefs.toBuilder()
            .setDisplayName(name)
            .build()
    }
}

Reaktivní pozorování změn

DataStore se integruje s architekturou MVVM přes ViewModel. Flow z DataStore je sbírán přes .stateIn a používán v UI. Při každé změně dat se UI automaticky aktualizuje — nejsou potřeba ruční aktualizace ani LiveData.

kotlin
class SettingsViewModel(
    private val dataStore: DataStore<Preferences>
) : ViewModel() {

    val uiState: StateFlow<SettingsUiState> =
        dataStore.data
            .map { prefs ->
                SettingsUiState(
                    isDarkMode = prefs[booleanPreferencesKey("dark_mode")] ?: false,
                    counter = prefs[intPreferencesKey("launch_count")] ?: 0
                )
            }
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(5000),
                initialValue = SettingsUiState()
            )
}

Často kladené otázky

Čím je DataStore lepší než SharedPreferences?

DataStore pracuje asynchronně (neblokuje UI vlákno), podporuje konkurentní přístup přes transakce a umožňuje reaktivní sledování změn přes Flow. SharedPreferences — synchronní API s rizikem ANR při velkých objemech dat a bez vestavěné podpory reaktivity.

Lze DataStore používat s Javou?

DataStore je napsán v Kotlinu a vyžaduje Kotlin Coroutines. Použití z Javy je možné, ale nepohodlné: je třeba vytvářet obálky s CompletableFuture nebo ručně spravovat coroutines. Pro Java projekty Google doporučuje ponechat SharedPreferences nebo přidat Kotlin do modulu.

Je DataStore vhodný pro ukládání velkých objemů dat?

DataStore načítá celý soubor do paměti při čtení, proto není vhodný pro ukládání seznamů nebo velkých objektů. Pro takové scénáře použijte Room nebo SQLite. DataStore je optimalizován pro nastavení a malá strukturovaná data — až stovky kilobajtů.

Jak zpracovat chybu poškozeného souboru DataStore?

Při vytváření DataStore lze předat corruptionHandler — funkci volanou při poškození souboru. Ve výchozím nastavení DataStore vyhazuje výjimku CorruptionException. V corruptionHandler lze vrátit prázdná data, poté DataStore přepíše soubor správným stavem.

Vyžaduje Proto DataStore povinně .proto soubor?

Ano, Proto DataStore vyžaduje definici schématu v .proto souboru a připojení protobuf-gradle-plugin. Pokud je projekt malý a data jednoduchá, je snazší použít Preferences DataStore — nevyžaduje dodatečnou konfiguraci sestavení.

Shrnutí

  • DataStore — moderní náhrada SharedPreferences pracující s Kotlin Coroutines a Flow
  • Preferences DataStore — jednoduchý klíč-hodnota bez schématu, vhodný pro nastavení
  • Proto DataStore — typované úložiště s protobuf schématem a automatickou migrací
  • Migrace ze SharedPreferences na DataStore je vestavěná přes SharedPreferencesMigration
  • Bezpečnost vláken — všechny operace jsou asynchronní, blokování UI je vyloučeno
  • Reaktivita — Flow informuje odběratele při každé změně dat
  • Doporučení — používejte DataStore ve všech nových Android projektech, migrujte stávající při práci s nastaveními

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také