DataStore: vad är det, grunderna i datalagring och ersättning för SharedPreferences

Författare: IT Sectr Publicerad: 2026-03-12 Lästid: 9 min

DataStore — en komponent från Jetpack-biblioteket avsedd för lagring av små mängder data i Android-applikationer. Till skillnad från SharedPreferences fungerar den asynkront och garanterar datakonsistens vid samtidig åtkomst. Enligt Google, 2024 använder DataStore Kotlin Coroutines och Flow, vilket gör det säkert för huvudtråden och lämpligt för reaktiva arkitekturer.

Huvudpunkter

  • DataStore — ersättning för SharedPreferences med asynkront API och datatyper via Protocol Buffers
  • Preferences DataStore — enkel Key-Store med läsning via Flow och transaktioner
  • Proto DataStore — typat lager med automatiska schemamigreringar
  • SharedPreferences — synkront API som blockerar UI-tråden vid stora volymer
  • Migrering utförs via ett speciellt SharedPreferencesMigration-gränssnitt utan dataförlust

Vad är DataStore?

DataStore — en lösning från Google för lokal datalagring i Android, presenterad 2020 som ett alternativ till SharedPreferences. Den stöder två lägen: Preferences DataStore (enkla nyckel-värdepar) och Proto DataStore (typat schema baserat på Protocol Buffers).

Den främsta fördelen — fullständig asynkronicitet: alla läsoperationer returnerar Flow från Kotlin Coroutines och skrivning utförs i coroutine-kontext. Detta eliminerar blockering av huvudtråden, vilket var ett typiskt problem med SharedPreferences vid arbete med stora datavolymer.

DataStore garanterar atomicitet av operationer: samtidiga skrivningar leder inte till dataförlust tack vare transaktionsmodellen. Om två komponenter samtidigt ändrar samma värde, hanterar DataStore konflikten korrekt via compare-and-swap-mekanismen.

Enligt Google I/O 2023 används DataStore i 40% av nya projekt på Android, och Google rekommenderar migrering från SharedPreferences i alla applikationer där stabilitet i inställningslagring krävs.

DataStore-arkitektur

I grunden av DataStore ligger SingleProcessDataStore — en implementering som fungerar inom en enda process. Den använder fillagring med lås på filnivå: vid dataskrivning låses filen, vilket förhindrar skada vid samtidig åtkomst.

DataStore hanterar automatiskt deserialiseringsfel: om filen är skadad returneras standardvärdet och filen skrivs över. Detta beteende konfigureras via corruptionHandler, som kan ställas in vid skapandet av DataStore.

Problem med SharedPreferences som DataStore löser

SharedPreferences lider av tre grundläggande problem: synkron läsning från disk på huvudtråden, brist på atomicitetsgarantier vid samtidiga skrivningar och omöjlighet att reaktivt spåra ändringar. DataStore löser alla tre: Flow för observation, fillås för atomicitet och asynkront API för trådsäkerhet.

Hur fungerar DataStore i Android?

DataStore lagrar data i filer på enhetens interna minne. Preferences DataStore använder ett filformat som liknar SharedPreferences, men med extra metadata för integritetskontroll. Proto DataStore använder binärformatet Protocol Buffers, vilket minskar filstorleken och påskyndar serialisering.

Vid dataläsning laddar DataStore hela filen i minnet en gång, varefter prenumeranter får aktuell status via Flow. Ändringar överförs automatiskt till alla aktiva prenumeranter — manuell registrering av listeners, som i SharedPreferences, krävs inte.

Funktionsprincip för Preferences DataStore

Preferences DataStore använder en inbyggd serialiseringsmekanism baserad på Map. Varje post är ett par av en sträng och en primitiv typ (Int, Boolean, Float, Long, String, Set). Data lagras i en XML-fil, liknande SharedPreferences, men med atomär skrivning via fillås.

Exempel på att skapa Preferences DataStore: tillägget preferencesDataStore på Context skapar en singleton med filnamnet. Vid upprepade anrop returneras samma instans — detta eliminerar duplicering av filer och förvirring med olika lagringsinstanser.

Funktionsprincip för Proto DataStore

Proto DataStore kräver att dataschemat definieras via en .proto-fil och kompilering med protobuf-plugin. Den genererade Java-klassen används som enda inmatningspunkt för alla fält — detta eliminerar skrivfel i nycklar, typiskt för SharedPreferences.

Proto DataStore-schemat definieras en gång och stöder tillägg av nya fält utan förlust av gamla data. Om ett fält med standardvärde läggs till i en ny version av applikationen, kommer den gamla filen att deserialiseras korrekt — bakåtkompatibilitet är inbyggd i protokollet.

Preferences DataStore och Proto DataStore: jämförelse

Valet mellan Preferences DataStore och Proto DataStore beror på datakomplexiteten och typkraven. Båda varianterna är asynkrona och transaktionsbaserade, men skiljer sig i nivån av type-safety och serialiseringsprestanda.

EgenskapPreferences DataStoreProto DataStore
TypningSvag (nyckel-värde)Stark (genererad klass)
SerialiseringXML (inbyggd)Protocol Buffers (protobuf)
FilstorlekStor (läsbar XML)Liten (binär)
KomplexitetLåg (utan .proto)Medel (kräver .proto)
SchemamigreringInget schemaAutomatisk (proto)
KompatibilitetSharedPreferences (via migrering)Endast Proto DataStore

När ska man välja Preferences DataStore

Preferences DataStore passar för enkla inställningar: funktionsaktiveringsflaggor, auktoriseringstokensträng, antal applikationsstarter. Om data är lite (upp till 10–15 nycklar) och inte kräver strikt schema — ger Preferences DataStore en minimal inträdesnivå utan att ansluta protobuf-plugin.

När ska man välja Proto DataStore

Proto DataStore är motiverat när datastrukturen är komplex eller kan ändras mellan applikationsversioner. Till exempel användarprofilinställningar eller A/B-testkonfiguration med 20+ fält. Protobuf ger stark typning och automatiska migreringar, vilket eliminerar körningsfel på grund av nyckelmissmatchning.

Hur migrerar man från SharedPreferences till DataStore

Google tillhandahåller en inbyggd migreringsmekanism via klassen SharedPreferencesMigration. Migreringen utförs en gång vid första starten efter applikationsuppdatering: DataStore läser data från SharedPreferences, skriver dem i sitt eget format och markerar migreringen som slutförd.

Migrering stöder anpassade transformationer: om nycklarna i SharedPreferences inte matchar de önskade DataStore-nycklarna, kan en transformationsfunktion definieras via SharedPreferencesMigration. Detta möjliggör omdöpning av nycklar och ändring av datatyper under migreringsprocessen.

Steg-för-steg-migrering

Första steget: lägg till DataStore i build.gradle och skapa en DataStore-instans med migrering: SharedPreferencesMigration accepterar namnet på SharedPreferences-filen och uppsättningen nycklar som ska överföras. Andra steget: ta bort all kod som fungerar via SharedPreferences och ersätt den med DataStore-anrop. Tredje — testa migreringen: vid första starten ska data visas i DataStore och den gamla SharedPreferences-filen ska sluta användas.

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

Exempel på DataStore-användning i kod

DataStore integreras enkelt i ett befintligt projekt. Nedan ges praktiska exempel för Preferences DataStore och Proto DataStore — båda demonstrerar läsning, skrivning och reaktiv observation av data.

Preferences DataStore: läsning och skrivning av inställningar

I detta exempel lagrar Preferences DataStore tre inställningar: mörkt tema, användarnamn och antal starter. Läsning sker via tillägget .data, som returnerar Flow. Skrivning — via suspend-funktionen .edit, som garanterar atomicitet av ändringar.

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: schema och användning

Proto DataStore kräver definition av en .proto-fil. Efter kompilering skapas klassen UserSettings, som används för läsning och skrivning. Schemaversioners migreringar beskrivs i samma .proto-fil och tillämpas automatiskt.

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

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

// Läsning från DataStore
val userPreferencesFlow: Flow<UserPreferences> =
    protoDataStore.data

// Skrivning av nya värden
suspend fun updateDisplayName(name: String) {
    protoDataStore.updateData { prefs ->
        prefs.toBuilder()
            .setDisplayName(name)
            .build()
    }
}

Reaktiv observation av ändringar

DataStore integreras med MVVM-arkitektur via ViewModel. Flow från DataStore samlas via .stateIn och används i UI. Vid varje dataändring uppdateras UI automatiskt — manuella uppdateringar eller LiveData behövs inte.

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()
            )
}

Vanliga frågor

Vad är bättre med DataStore än SharedPreferences?

DataStore fungerar asynkront (blockerar inte UI-tråden), stöder samtidig åtkomst via transaktioner och möjliggör reaktiv prenumeration på ändringar via Flow. SharedPreferences — synkront API med ANR-risk vid stora datavolymer och utan inbyggt stöd för reaktivitet.

Kan DataStore användas med Java?

DataStore är skrivet i Kotlin och kräver Kotlin Coroutines. Att använda det från Java är möjligt men obekvämt: man måste skapa omslag med CompletableFuture eller manuellt hantera coroutines. För Java-projekt rekommenderar Google att behålla SharedPreferences eller lägga till Kotlin i modulen.

Är DataStore lämpligt för lagring av stora datavolymer?

DataStore laddar hela filen i minnet vid läsning, så det är inte lämpligt för lagring av listor eller stora objekt. För sådana scenarier, använd Room eller SQLite. DataStore är optimerat för inställningar och små strukturerade data — upp till hundratals kilobyte.

Hur hanterar man ett fel med skadad DataStore-fil?

Vid skapandet av DataStore kan corruptionHandler skickas — en funktion som anropas vid filskada. Som standard kastar DataStore ett CorruptionException. I corruptionHandler kan tom data returneras, varefter DataStore skriver över filen med korrekt tillstånd.

Kräver Proto DataStore obligatoriskt en .proto-fil?

Ja, Proto DataStore kräver att schemat definieras i en .proto-fil och att protobuf-gradle-plugin ansluts. Om projektet är litet och data enkel, är det enklare att använda Preferences DataStore — det kräver ingen extra byggkonfiguration.

Sammanfattning

  • DataStore — modern ersättning för SharedPreferences som fungerar med Kotlin Coroutines och Flow
  • Preferences DataStore — enkel nyckel-värde utan schema, lämplig för inställningar
  • Proto DataStore — typat lager med protobuf-schema och automatisk migrering
  • Migrering från SharedPreferences till DataStore är inbyggd via SharedPreferencesMigration
  • Trådsäkerhet — alla operationer är asynkrona, UI-blockering är utesluten
  • Reaktivitet — Flow meddelar prenumeranter vid varje dataändring
  • Rekommendation — använd DataStore i alla nya Android-projekt, migrera befintliga vid arbete med inställningar

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också