DataStore: ce este, bazele stocării datelor și înlocuitor pentru SharedPreferences

Autor: IT Sectr Publicat: 2026-03-12 Timp de citire: 9 min

DataStore — o componentă din biblioteca Jetpack destinată stocării volumelor mici de date în aplicațiile Android. Spre deosebire de SharedPreferences, funcționează asincron și garantează consistența datelor la acces concurent. Conform datelor Google, 2024, DataStore utilizează Kotlin Coroutines și Flow, ceea ce îl face sigur pentru firul principal și potrivit pentru arhitecturi reactive.

Principalele puncte

  • DataStore — înlocuitor pentru SharedPreferences cu API asincron și tipuri de date prin Protocol Buffers
  • Preferences DataStore — Key-Store simplu cu citire prin Flow și tranzacții
  • Proto DataStore — depozit tipizat cu migrări automate de schemă
  • SharedPreferences — API sincron care blochează firul UI la volume mari
  • Migrarea se realizează prin interfața SharedPreferencesMigration fără pierderea datelor

Ce este DataStore?

DataStore — o soluție de la Google pentru stocarea locală a datelor în Android, prezentată în 2020 ca alternativă la SharedPreferences. Suportă două moduri: Preferences DataStore (perechi cheie-valoare simple) și Proto DataStore (schemă tipizată bazată pe Protocol Buffers).

Principalul avantaj — asincronism complet: toate operațiile de citire returnează Flow din Kotlin Coroutines, iar scrierea se execută în context coroutine. Aceasta elimină blocarea firului principal, care era o problemă tipică a SharedPreferences la lucrul cu volume mari de date.

DataStore garantează atomicitatea operațiilor: scrierile concurente nu duc la pierderea datelor datorită modelului tranzacțional. Dacă două componente modifică simultan aceeași valoare, DataStore gestionează corect conflictul prin mecanismul compare-and-swap.

Conform datelor Google I/O 2023, DataStore este utilizat în 40% din proiectele noi pe Android, iar Google recomandă migrarea de la SharedPreferences în toate aplicațiile care necesită stabilitate la stocarea setărilor.

Arhitectura DataStore

La baza DataStore stă SingleProcessDataStore — o implementare care funcționează în cadrul unui singur proces. Utilizează stocare pe fișier cu blocaje la nivel de fișier: la scrierea datelor, fișierul este blocat, prevenind deteriorarea la acces concurent.

DataStore gestionează automat erorile de deserializare: dacă fișierul este deteriorat, returnează valoarea implicită și rescrie fișierul. Acest comportament se configurează prin corruptionHandler, care poate fi setat la crearea DataStore.

Problemele SharedPreferences pe care le rezolvă DataStore

SharedPreferences suferă de trei probleme fundamentale: citirea sincronă de pe disc pe firul principal, lipsa garanțiilor de atomicitate la scrieri concurente și imposibilitatea urmăririi reactive a modificărilor. DataStore le rezolvă pe toate trei: Flow pentru observare, blocaj de fișier pentru atomicitate și API asincron pentru siguranța firelor.

Cum funcționează DataStore în Android?

DataStore stochează datele în fișiere pe memoria internă a dispozitivului. Preferences DataStore utilizează un format de fișier similar cu SharedPreferences, dar cu metadate suplimentare pentru verificarea integrității. Proto DataStore utilizează formatul binar Protocol Buffers, ceea ce reduce dimensiunea fișierului și accelerează serializarea.

La citirea datelor, DataStore încarcă întregul fișier în memorie o singură dată, după care abonații primesc starea curentă prin Flow. Modificările sunt transmise automat tuturor abonaților activi — nu este necesară înregistrarea manuală a listener-ilor, ca în SharedPreferences.

Principiul de funcționare Preferences DataStore

Preferences DataStore utilizează un mecanism intern de serializare bazat pe Map. Fiecare intrare este o pereche de șir și tip primitiv (Int, Boolean, Float, Long, String, Set). Datele sunt stocate într-un fișier XML, similar cu SharedPreferences, dar cu scriere atomică prin blocaj de fișier.

Exemplu de creare Preferences DataStore: extensia preferencesDataStore pe Context creează un singleton cu numele fișierului. La apeluri repetate se returnează aceeași instanță — aceasta elimină duplicarea fișierelor și confuzia cu diferite instanțe de depozit.

Principiul de funcționare Proto DataStore

Proto DataStore necesită definirea schemei de date prin fișier .proto și compilarea cu pluginul protobuf. Clasa Java generată este utilizată ca unic punct de intrare pentru toate câmpurile — aceasta elimină greșelile de tastare în chei, tipice pentru SharedPreferences.

Schema Proto DataStore se definește o singură dată și suportă adăugarea de câmpuri noi fără pierderea datelor vechi. Dacă în noua versiune a aplicației se adaugă un câmp cu valoare implicită, fișierul vechi va fi deserializat corect — compatibilitatea inversă este încorporată în protocol.

Preferences DataStore și Proto DataStore: comparație

Alegerea între Preferences DataStore și Proto DataStore depinde de complexitatea datelor și cerințele de tipizare. Ambele variante sunt asincrone și tranzacționale, dar diferă prin nivelul de type-safety și performanța serializării.

CaracteristicăPreferences DataStoreProto DataStore
TipizareSlabă (cheie-valoare)Puternică (clasă generată)
SerializareXML (încorporată)Protocol Buffers (protobuf)
Dimensiune fișierMare (XML citibil)Mică (binar)
ComplexitateScăzută (fără .proto)Medie (necesită .proto)
Migrare schemăFără schemăAutomată (proto)
CompatibilitateSharedPreferences (prin migrare)Doar Proto DataStore

Când să alegem Preferences DataStore

Preferences DataStore este potrivit pentru setări simple: flaguri de activare a funcțiilor, șirul tokenului de autentificare, numărul de lansări ale aplicației. Dacă datele sunt puține (până la 10–15 chei) și nu necesită o schemă strictă — Preferences DataStore oferă un prag minim de intrare fără conectarea pluginului protobuf.

Când să alegem Proto DataStore

Proto DataStore este justificat când structura datelor este complexă sau se poate schimba între versiunile aplicației. De exemplu, setările profilului utilizatorului sau configurarea testelor A/B cu 20+ câmpuri. Protobuf oferă tipizare puternică și migrări automate, ceea ce elimină erorile de execuție din cauza nepotrivirii cheilor.

Cum să migrăm de la SharedPreferences la DataStore

Google oferă un mecanism încorporat de migrare prin clasa SharedPreferencesMigration. Migrarea se execută o singură dată la prima lansare după actualizarea aplicației: DataStore citește datele din SharedPreferences, le scrie în formatul său și marchează migrarea ca finalizată.

Migrarea suportă transformări personalizate: dacă în SharedPreferences cheile nu corespund cheilor dorite în DataStore, se poate defini o funcție de transformare prin SharedPreferencesMigration. Aceasta permite redenumirea cheilor și schimbarea tipurilor de date în procesul de migrare.

Migrare pas cu pas

Primul pas: adăugați DataStore în build.gradle și creați o instanță DataStore cu migrare: SharedPreferencesMigration primește numele fișierului SharedPreferences și setul de chei care trebuie transferate. Al doilea pas: ștergeți tot codul care funcționează prin SharedPreferences și înlocuiți-l cu apeluri DataStore. Al treilea — testați migrarea: la prima lansare datele trebuie să apară în DataStore, iar vechiul fișier SharedPreferences să nu mai fie utilizat.

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

Exemple de utilizare a DataStore în cod

DataStore se integrează ușor în proiectul existent. Mai jos sunt prezentate exemple practice pentru Preferences DataStore și Proto DataStore — ambele demonstrează citirea, scrierea și observarea reactivă a datelor.

Preferences DataStore: citirea și scrierea setărilor

În acest exemplu Preferences DataStore stochează trei setări: tema întunecată, numele utilizatorului și numărul de lansări. Citirea se realizează prin extensia .data, care returnează Flow. Scrierea — prin funcția suspend .edit, care garantează atomicitatea modificărilor.

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: schemă și utilizare

Proto DataStore necesită definirea unui fișier .proto. După compilare, se creează clasa UserSettings, utilizată pentru citire și scriere. Migrările versiunilor de schemă sunt descrise în același fișier .proto și aplicate automat.

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

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

// Citire din DataStore
val userPreferencesFlow: Flow<UserPreferences> =
    protoDataStore.data

// Scrierea noilor valori
suspend fun updateDisplayName(name: String) {
    protoDataStore.updateData { prefs ->
        prefs.toBuilder()
            .setDisplayName(name)
            .build()
    }
}

Observarea reactivă a modificărilor

DataStore se integrează cu arhitectura MVVM prin ViewModel. Flow-ul din DataStore este colectat prin .stateIn și utilizat în UI. La fiecare modificare a datelor, UI se actualizează automat — nu sunt necesare actualizări manuale sau 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()
            )
}

Întrebări frecvente

Cu ce este DataStore mai bun decât SharedPreferences?

DataStore funcționează asincron (nu blochează firul UI), suportă acces concurent prin tranzacții și permite abonarea reactivă la modificări prin Flow. SharedPreferences — API sincron cu risc de ANR la volume mari de date și fără suport încorporat pentru reactivitate.

Se poate utiliza DataStore cu Java?

DataStore este scris în Kotlin și necesită Kotlin Coroutines. Utilizarea lui din Java este posibilă, dar incomodă: trebuie create wrapper-e cu CompletableFuture sau gestionate manual coroutine-urile. Pentru proiectele Java, Google recomandă să păstrați SharedPreferences sau să adăugați Kotlin în modul.

DataStore este potrivit pentru stocarea volumelor mari de date?

DataStore încarcă întregul fișier în memorie la citire, deci nu este potrivit pentru stocarea listelor sau obiectelor mari. Pentru astfel de scenarii, utilizați Room sau SQLite. DataStore este optimizat pentru setări și date structurate mici — până la sute de kiloocteți.

Cum gestionăm eroarea unui fișier DataStore deteriorat?

La crearea DataStore se poate transmite corruptionHandler — o funcție apelată la deteriorarea fișierului. Implicit, DataStore aruncă excepția CorruptionException. În corruptionHandler se pot returna date goale, după care DataStore rescrie fișierul cu starea corectă.

Proto DataStore necesită obligatoriu un fișier .proto?

Da, Proto DataStore necesită definirea schemei într-un fișier .proto și conectarea pluginului protobuf-gradle-plugin. Dacă proiectul este mic și datele simple, este mai ușor să utilizați Preferences DataStore — nu necesită configurare suplimentară de build.

Concluzii

  • DataStore — înlocuitor modern pentru SharedPreferences care funcționează cu Kotlin Coroutines și Flow
  • Preferences DataStore — cheie-valoare simplă fără schemă, potrivit pentru setări
  • Proto DataStore — depozit tipizat cu schemă protobuf și auto-migrare
  • Migrarea de la SharedPreferences la DataStore este încorporată prin SharedPreferencesMigration
  • Siguranța firelor — toate operațiile sunt asincrone, blocarea UI este exclusă
  • Reactivitate — Flow notifică abonații la fiecare modificare a datelor
  • Recomandare — utilizați DataStore în toate proiectele noi Android, migrați proiectele existente când lucrați cu setări

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și