DataStore: τι είναι, βασικές αρχές αποθήκευσης δεδομένων και αντικατάσταση SharedPreferences

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-03-12 Χρόνος ανάγνωσης: 9 λεπ

DataStore — ένα στοιχείο από τη βιβλιοθήκη Jetpack που προορίζεται για την αποθήκευση μικρών όγκων δεδομένων σε εφαρμογές Android. Σε αντίθεση με τα SharedPreferences, λειτουργεί ασύγχρονα και εγγυάται τη συνέπεια των δεδομένων κατά την ταυτόχρονη πρόσβαση. Σύμφωνα με στοιχεία της Google, 2024, το DataStore χρησιμοποιεί Kotlin Coroutines και Flow, καθιστώντας το ασφαλές για το κύριο νήμα και κατάλληλο για αντιδραστικές αρχιτεκτονικές.

Κύρια σημεία

  • DataStore — αντικατάσταση SharedPreferences με ασύγχρονο API και τύπους δεδομένων μέσω Protocol Buffers
  • Preferences DataStore — απλό Key-Store με ανάγνωση μέσω Flow και συναλλαγές
  • Proto DataStore — τυποποιημένος αποθηκευτικός χώρος με αυτόματες μεταναστεύσεις σχήματος
  • SharedPreferences — σύγχρονο API που μπλοκάρει το νήμα UI σε μεγάλους όγκους
  • Μετανάστευση εκτελείται μέσω ειδικής διεπαφής SharedPreferencesMigration χωρίς απώλεια δεδομένων

Τι είναι το DataStore;

DataStore — μια λύση από την Google για τοπική αποθήκευση δεδομένων στο Android, που παρουσιάστηκε το 2020 ως εναλλακτική των SharedPreferences. Υποστηρίζει δύο λειτουργίες: Preferences DataStore (απλά ζεύγη κλειδιού-τιμής) και Proto DataStore (τυποποιημένο σχήμα βασισμένο σε Protocol Buffers).

Το κύριο πλεονέκτημα — πλήρης ασυγχρονία: όλες οι λειτουργίες ανάγνωσης επιστρέφουν Flow από Kotlin Coroutines, και η εγγραφή εκτελείται σε περιβάλλον coroutine. Αυτό εξαλείφει το μπλοκάρισμα του κύριου νήματος, που ήταν ένα τυπικό πρόβλημα των SharedPreferences κατά την εργασία με μεγάλους όγκους δεδομένων.

Το DataStore εγγυάται την ατομικότητα των λειτουργιών: οι ταυτόχρονες εγγραφές δεν οδηγούν σε απώλεια δεδομένων χάρη στο μοντέλο συναλλαγών. Εάν δύο στοιχεία τροποποιούν ταυτόχρονα την ίδια τιμή, το DataStore χειρίζεται σωστά τη σύγκρουση μέσω του μηχανισμού compare-and-swap.

Σύμφωνα με στοιχεία του Google I/O 2023, το DataStore χρησιμοποιείται στο 40% των νέων έργων στο Android, και η Google συνιστά μετανάστευση από SharedPreferences σε όλες τις εφαρμογές όπου απαιτείται σταθερότητα αποθήκευσης ρυθμίσεων.

Αρχιτεκτονική DataStore

Στη βάση του DataStore βρίσκεται το SingleProcessDataStore — μια υλοποίηση που λειτουργεί στο πλαίσιο μιας διεργασίας. Χρησιμοποιεί αποθήκευση αρχείων με κλειδώματα σε επίπεδο αρχείου: κατά την εγγραφή δεδομένων, το αρχείο κλειδώνεται, αποτρέποντας τη φθορά κατά την ταυτόχρονη πρόσβαση.

Το DataStore χειρίζεται αυτόματα σφάλματα αποσειριοποίησης: εάν το αρχείο είναι κατεστραμμένο, επιστρέφει την προεπιλεγμένη τιμή και ξαναγράφει το αρχείο. Αυτή η συμπεριφορά διαμορφώνεται μέσω του corruptionHandler, που μπορεί να οριστεί κατά τη δημιουργία του DataStore.

Προβλήματα SharedPreferences που λύνει το DataStore

SharedPreferences υποφέρει από τρία θεμελιώδη προβλήματα: σύγχρονη ανάγνωση από το δίσκο στο κύριο νήμα, έλλειψη εγγυήσεων ατομικότητας σε ταυτόχρονες εγγραφές και αδυναμία αντιδραστικής παρακολούθησης αλλαγών. Το DataStore λύνει και τα τρία: Flow για παρατήρηση, κλείδωμα αρχείου για ατομικότητα και ασύγχρονο API για ασφάλεια νημάτων.

Πώς λειτουργεί το DataStore στο Android;

DataStore αποθηκεύει δεδομένα σε αρχεία στην εσωτερική μνήμη της συσκευής. Το Preferences DataStore χρησιμοποιεί μορφή αρχείου παρόμοια με τα SharedPreferences, αλλά με πρόσθετα μεταδεδομένα για έλεγχο ακεραιότητας. Το Proto DataStore χρησιμοποιεί τη δυαδική μορφή Protocol Buffers, που μειώνει το μέγεθος αρχείου και επιταχύνει τη σειριοποίηση.

Κατά την ανάγνωση δεδομένων, το DataStore φορτώνει ολόκληρο το αρχείο στη μνήμη μία φορά, μετά την οποία οι συνδρομητές λαμβάνουν την τρέχουσα κατάσταση μέσω Flow. Οι αλλαγές μεταδίδονται αυτόματα σε όλους τους ενεργούς συνδρομητές — δεν απαιτείται χειροκίνητη εγγραφή listener, όπως στα SharedPreferences.

Αρχή λειτουργίας Preferences DataStore

Preferences DataStore χρησιμοποιεί έναν ενσωματωμένο μηχανισμό σειριοποίησης βασισμένο σε Map. Κάθε καταχώρηση είναι ένα ζεύγος συμβολοσειράς και πρωτόγονου τύπου (Int, Boolean, Float, Long, String, Set). Τα δεδομένα αποθηκεύονται σε αρχείο XML, παρόμοιο με SharedPreferences, αλλά με ατομική εγγραφή μέσω κλειδώματος αρχείου.

Παράδειγμα δημιουργίας Preferences DataStore: η επέκταση preferencesDataStore στο Context δημιουργεί ένα singleton με το όνομα αρχείου. Σε επαναλαμβανόμενες κλήσεις επιστρέφεται το ίδιο στιγμιότυπο — αυτό εξαλείφει τον διπλασιασμό αρχείων και τη σύγχυση με διαφορετικά στιγμιότυπα αποθηκευτικού χώρου.

Αρχή λειτουργίας Proto DataStore

Proto DataStore απαιτεί τον ορισμό σχήματος δεδομένων μέσω αρχείου .proto και μεταγλώττιση με χρήση του protobuf plugin. Η παραγόμενη κλάση Java χρησιμοποιείται ως μοναδικό σημείο εισόδου για όλα τα πεδία — αυτό εξαλείφει τυπογραφικά λάθη σε κλειδιά, τυπικά για SharedPreferences.

Το σχήμα Proto DataStore ορίζεται μία φορά και υποστηρίζει την προσθήκη νέων πεδίων χωρίς απώλεια παλαιών δεδομένων. Εάν στη νέα έκδοση της εφαρμογής προστεθεί ένα πεδίο με προεπιλεγμένη τιμή, το παλιό αρχείο θα αποσειριοποιηθεί σωστά — η προς τα πίσω συμβατότητα είναι ενσωματωμένη στο πρωτόκολλο.

Preferences DataStore και Proto DataStore: σύγκριση

Η επιλογή μεταξύ Preferences DataStore και Proto DataStore εξαρτάται από την πολυπλοκότητα των δεδομένων και τις απαιτήσεις τυποποίησης. Και οι δύο παραλλαγές είναι ασύγχρονες και συναλλακτικές, αλλά διαφέρουν στο επίπεδο type-safety και στην απόδοση σειριοποίησης.

ΧαρακτηριστικόPreferences DataStoreProto DataStore
ΤυποποίησηΑσθενής (κλειδί-τιμή)Ισχυρή (παραγόμενη κλάση)
ΣειριοποίησηXML (ενσωματωμένη)Protocol Buffers (protobuf)
Μέγεθος αρχείουΜεγάλο (αναγνώσιμο XML)Μικρό (δυαδικό)
ΠολυπλοκότηταΧαμηλή (χωρίς .proto)Μεσαία (απαιτεί .proto)
Μετανάστευση σχήματοςΔεν υπάρχει σχήμαΑυτόματη (proto)
ΣυμβατότηταSharedPreferences (μέσω μετανάστευσης)Μόνο Proto DataStore

Πότε να επιλέξετε Preferences DataStore

Preferences DataStore είναι κατάλληλο για απλές ρυθμίσεις: σημαίες ενεργοποίησης λειτουργιών, συμβολοσειρά διακριτικού εξουσιοδότησης, αριθμός εκκινήσεων εφαρμογής. Εάν τα δεδομένα είναι λίγα (έως 10–15 κλειδιά) και δεν απαιτούν αυστηρό σχήμα — το Preferences DataStore παρέχει ελάχιστο όριο εισόδου χωρίς σύνδεση του protobuf plugin.

Πότε να επιλέξετε Proto DataStore

Proto DataStore δικαιολογείται όταν η δομή δεδομένων είναι πολύπλοκη ή μπορεί να αλλάξει μεταξύ εκδόσεων εφαρμογής. Για παράδειγμα, ρυθμίσεις προφίλ χρήστη ή διαμόρφωση δοκιμών A/B με 20+ πεδία. Το Protobuf παρέχει ισχυρή τυποποίηση και αυτόματες μεταναστεύσεις, που εξαλείφει σφάλματα χρόνου εκτέλεσης λόγω αναντιστοιχίας κλειδιών.

Πώς να μεταναστεύσετε από SharedPreferences σε DataStore

Google παρέχει ενσωματωμένο μηχανισμό μετανάστευσης μέσω της κλάσης SharedPreferencesMigration. Η μετανάστευση εκτελείται μία φορά κατά την πρώτη εκκίνηση μετά την ενημέρωση της εφαρμογής: το DataStore διαβάζει δεδομένα από SharedPreferences, τα γράφει στη δική του μορφή και σηματοδοτεί τη μετανάστευση ως ολοκληρωμένη.

Η μετανάστευση υποστηρίζει προσαρμοσμένους μετασχηματισμούς: εάν στα SharedPreferences τα κλειδιά δεν ταιριάζουν με τα επιθυμητά κλειδιά DataStore, μπορεί να οριστεί μια συνάρτηση μετασχηματισμού μέσω SharedPreferencesMigration. Αυτό επιτρέπει τη μετονομασία κλειδιών και την αλλαγή τύπων δεδομένων κατά τη διαδικασία μετανάστευσης.

Βήμα προς βήμα μετανάστευση

Πρώτο βήμα: προσθέστε το DataStore στο build.gradle και δημιουργήστε ένα στιγμιότυπο DataStore με μετανάστευση: το SharedPreferencesMigration δέχεται το όνομα του αρχείου SharedPreferences και το σύνολο κλειδιών που πρέπει να μεταφερθούν. Δεύτερο βήμα: αφαιρέστε όλο τον κώδικα που λειτουργεί μέσω SharedPreferences και αντικαταστήστε τον με κλήσεις DataStore. Τρίτο — ελέγξτε τη μετανάστευση: κατά την πρώτη εκκίνηση τα δεδομένα πρέπει να εμφανιστούν στο DataStore και το παλιό αρχείο SharedPreferences πρέπει να σταματήσει να χρησιμοποιείται.

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

Παραδείγματα χρήσης DataStore σε κώδικα

DataStore ενσωματώνεται εύκολα σε ένα υπάρχον έργο. Παρακάτω δίνονται πρακτικά παραδείγματα για Preferences DataStore και Proto DataStore — και τα δύο δείχνουν ανάγνωση, εγγραφή και αντιδραστική παρατήρηση δεδομένων.

Preferences DataStore: ανάγνωση και εγγραφή ρυθμίσεων

Σε αυτό το παράδειγμα το Preferences DataStore αποθηκεύει τρεις ρυθμίσεις: σκοτεινό θέμα, όνομα χρήστη και αριθμό εκκινήσεων. Η ανάγνωση γίνεται μέσω της επέκτασης .data, που επιστρέφει Flow. Η εγγραφή — μέσω της συνάρτησης suspend .edit, που εγγυάται την ατομικότητα των αλλαγών.

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: σχήμα και χρήση

Proto DataStore απαιτεί τον ορισμό ενός αρχείου .proto. Μετά τη μεταγλώττιση, δημιουργείται η κλάση UserSettings, που χρησιμοποιείται για ανάγνωση και εγγραφή. Οι μεταναστεύσεις εκδόσεων σχήματος περιγράφονται στο ίδιο αρχείο .proto και εφαρμόζονται αυτόματα.

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

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

// Ανάγνωση από το DataStore
val userPreferencesFlow: Flow<UserPreferences> =
    protoDataStore.data

// Εγγραφή νέων τιμών
suspend fun updateDisplayName(name: String) {
    protoDataStore.updateData { prefs ->
        prefs.toBuilder()
            .setDisplayName(name)
            .build()
    }
}

Αντιδραστική παρατήρηση αλλαγών

DataStore ενσωματώνεται με την αρχιτεκτονική MVVM μέσω ViewModel. Το Flow από το DataStore συλλέγεται μέσω .stateIn και χρησιμοποιείται στο UI. Σε κάθε αλλαγή δεδομένων, το UI ενημερώνεται αυτόματα — δεν απαιτούνται χειροκίνητες ενημερώσεις ή 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()
            )
}

Συχνές ερωτήσεις

Σε τι είναι καλύτερο το DataStore από τα SharedPreferences;

DataStore λειτουργεί ασύγχρονα (δεν μπλοκάρει το νήμα UI), υποστηρίζει ταυτόχρονη πρόσβαση μέσω συναλλαγών και επιτρέπει αντιδραστική εγγραφή σε αλλαγές μέσω Flow. SharedPreferences — σύγχρονο API με κίνδυνο ANR σε μεγάλους όγκους δεδομένων και χωρίς ενσωματωμένη υποστήριξη αντιδραστικότητας.

Μπορεί το DataStore να χρησιμοποιηθεί με Java;

DataStore είναι γραμμένο σε Kotlin και απαιτεί Kotlin Coroutines. Η χρήση του από Java είναι δυνατή αλλά άβολη: πρέπει να δημιουργηθούν περιτυλίγματα με CompletableFuture ή να γίνει χειροκίνητη διαχείριση coroutines. Για έργα Java, η Google συνιστά να διατηρήσετε SharedPreferences ή να προσθέσετε Kotlin στην ενότητα.

Είναι το DataStore κατάλληλο για αποθήκευση μεγάλων όγκων δεδομένων;

DataStore φορτώνει ολόκληρο το αρχείο στη μνήμη κατά την ανάγνωση, επομένως δεν είναι κατάλληλο για αποθήκευση λιστών ή μεγάλων αντικειμένων. Για τέτοια σενάρια, χρησιμοποιήστε Room ή SQLite. Το DataStore είναι βελτιστοποιημένο για ρυθμίσεις και μικρά δομημένα δεδομένα — έως εκατοντάδες kilobyte.

Πώς να χειριστείτε σφάλμα κατεστραμμένου αρχείου DataStore;

Κατά τη δημιουργία DataStore μπορεί να μεταβιβαστεί ένα corruptionHandler — μια συνάρτηση που καλείται όταν το αρχείο είναι κατεστραμμένο. Από προεπιλογή, το DataStore ρίχνει εξαίρεση CorruptionException. Στο corruptionHandler μπορούν να επιστραφούν κενά δεδομένα, μετά από τα οποία το DataStore ξαναγράφει το αρχείο με τη σωστή κατάσταση.

Απαιτεί το Proto DataStore υποχρεωτικά αρχείο .proto;

Ναι, το Proto DataStore απαιτεί τον ορισμό σχήματος σε αρχείο .proto και τη σύνδεση του protobuf-gradle-plugin. Εάν το έργο είναι μικρό και τα δεδομένα απλά, είναι ευκολότερο να χρησιμοποιήσετε Preferences DataStore — δεν απαιτεί πρόσθετη διαμόρφωση build.

Σύνοψη

  • DataStore — σύγχρονη αντικατάσταση SharedPreferences που λειτουργεί με Kotlin Coroutines και Flow
  • Preferences DataStore — απλό κλειδί-τιμή χωρίς σχήμα, κατάλληλο για ρυθμίσεις
  • Proto DataStore — τυποποιημένος αποθηκευτικός χώρος με σχήμα protobuf και αυτόματη μετανάστευση
  • Μετανάστευση από SharedPreferences σε DataStore είναι ενσωματωμένη μέσω SharedPreferencesMigration
  • Ασφάλεια νημάτων — όλες οι λειτουργίες είναι ασύγχρονες, αποκλείεται το μπλοκάρισμα UI
  • Αντιδραστικότητα — το Flow ειδοποιεί τους συνδρομητές σε κάθε αλλαγή δεδομένων
  • Σύσταση — χρησιμοποιήστε DataStore σε όλα τα νέα έργα Android, μεταναστεύστε υπάρχοντα όταν εργάζεστε με ρυθμίσεις

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης