DataStore : qu'est-ce que c'est, bases du stockage de données et remplacement de SharedPreferences

Auteur : IT Sectr Publié le : 2026-03-12 Temps de lecture : 9 min

DataStore est un composant de la bibliothèque Jetpack conçu pour stocker de petites quantités de données dans les applications Android. Contrairement à SharedPreferences, il fonctionne de manière asynchrone et garantit la cohérence des données en cas d'accès concurrent. Selon Google, 2024, DataStore utilise Kotlin Coroutines et Flow, ce qui le rend sûr pour le thread principal et adapté aux architectures réactives.

Points Clés

  • DataStore — un remplacement de SharedPreferences avec une API asynchrone et des types de données via Protocol Buffers
  • Preferences DataStore — un simple magasin clé-valeur avec lecture via Flow et transactions
  • Proto DataStore — un stockage typé avec des migrations de schéma automatiques
  • SharedPreferences — API synchrone bloquant le thread UI avec de gros volumes
  • Migration effectuée via l'interface SharedPreferencesMigration sans perte de données

Qu'est-ce que DataStore ?

DataStore est une solution de Google pour le stockage local de données dans Android, présentée en 2020 comme alternative à SharedPreferences. Il prend en charge deux modes : Preferences DataStore (paires simples clé-valeur) et Proto DataStore (schéma typé basé sur Protocol Buffers).

Le principal avantage est l'asynchronie totale : toutes les opérations de lecture retournent un Flow de Kotlin Coroutines, et les écritures sont effectuées dans un contexte de coroutine. Cela élimine le blocage du thread principal, qui était un problème typique de SharedPreferences lors du traitement de gros volumes de données.

DataStore garantit l'atomicité des opérations : les écritures concurrentes n'entraînent pas de perte de données grâce à son modèle transactionnel. Si deux composants modifient la même valeur simultanément, DataStore gère correctement le conflit via un mécanisme compare-and-swap.

Selon Google I/O 2023, DataStore est utilisé dans 40 % des nouveaux projets Android, et Google recommande de migrer depuis SharedPreferences dans toutes les applications où la stabilité du stockage des paramètres est requise.

Architecture de DataStore

Au cœur de DataStore se trouve SingleProcessDataStore — une implémentation qui opère au sein d'un seul processus. Il utilise un stockage basé sur des fichiers avec verrouillage au niveau du fichier : lors de l'écriture de données, le fichier est verrouillé, empêchant la corruption en cas d'accès concurrent.

DataStore gère automatiquement les erreurs de désérialisation : si le fichier est corrompu, il retourne une valeur par défaut et réécrit le fichier. Ce comportement est configurable via corruptionHandler, qui peut être défini lors de la création du DataStore.

Problèmes de SharedPreferences résolus par DataStore

SharedPreferences souffre de trois problèmes fondamentaux : lecture synchrone du disque sur le thread principal, absence de garanties d'atomicité pour les écritures concurrentes et impossibilité de suivre les modifications de manière réactive. DataStore résout les trois : Flow pour l'observation, verrouillage de fichier pour l'atomicité et API asynchrone pour la sécurité des threads.

Comment DataStore fonctionne-t-il dans Android ?

DataStore stocke les données dans des fichiers sur le stockage interne de l'appareil. Preferences DataStore utilise un format de fichier similaire à SharedPreferences mais avec des métadonnées supplémentaires pour la vérification d'intégrité. Proto DataStore utilise le format binaire Protocol Buffers, ce qui réduit la taille du fichier et accélère la sérialisation.

Lors de la lecture des données, DataStore charge l'intégralité du fichier en mémoire une fois, après quoi les abonnés reçoivent l'état actuel via Flow. Les modifications sont diffusées automatiquement à tous les abonnés actifs — aucun enregistrement manuel d'écouteurs n'est requis, contrairement à SharedPreferences.

Comment fonctionne Preferences DataStore

Preferences DataStore utilise un mécanisme de sérialisation intégré basé sur une Map. Chaque entrée est une paire d'une chaîne et d'un type primitif (Int, Boolean, Float, Long, String, Set). Les données sont stockées dans un fichier XML, similaire à SharedPreferences, mais avec une écriture atomique via le verrouillage de fichier.

Exemple de création de Preferences DataStore : l'extension preferencesDataStore sur Context crée un singleton avec le nom du fichier. Lors d'appels répétés, la même instance est retournée — cela élimine la duplication de fichiers et la confusion entre différentes instances de stockage.

Comment fonctionne Proto DataStore

Proto DataStore nécessite la définition d'un schéma de données via un fichier .proto et la compilation avec le plugin protobuf. La classe Java générée est utilisée comme point d'entrée unique pour tous les champs — cela élimine les fautes de frappe dans les clés, courantes avec SharedPreferences.

Le schéma Proto DataStore est défini une fois et prend en charge l'ajout de nouveaux champs sans perdre les anciennes données. Si une nouvelle version de l'application ajoute un champ avec une valeur par défaut, l'ancien fichier sera correctement désérialisé — la compatibilité ascendante est intégrée dans le protocole.

Preferences DataStore vs Proto DataStore : Comparaison

Le choix entre Preferences DataStore et Proto DataStore dépend de la complexité des données et des exigences de typage. Les deux options sont asynchrones et transactionnelles, mais diffèrent en matière de sécurité de type et de performances de sérialisation.

CaractéristiquePreferences DataStoreProto DataStore
TypageFaible (clé-valeur)Fort (classe générée)
SérialisationXML (intégrée)Protocol Buffers (protobuf)
Taille du fichierGrande (XML lisible)Petite (binaire)
ComplexitéFaible (sans .proto)Moyenne (nécessite .proto)
Migration de schémaPas de schémaAutomatique (proto)
CompatibilitéSharedPreferences (via migration)Proto DataStore uniquement

Quand choisir Preferences DataStore

Preferences DataStore convient pour les paramètres simples : indicateurs de fonctionnalités, chaîne de jeton d'autorisation, nombre de lancements de l'application. Si les données sont peu nombreuses (jusqu'à 10–15 clés) et ne nécessitent pas de schéma strict, Preferences DataStore offre un seuil d'entrée minimal sans connexion du plugin protobuf.

Quand choisir Proto DataStore

Proto DataStore est justifié lorsque la structure des données est complexe ou peut changer entre les versions de l'application. Par exemple, les paramètres de profil utilisateur ou la configuration de tests A/B avec 20+ champs. Protobuf fournit un typage fort et des migrations automatiques, éliminant les erreurs d'exécution dues à des discordances de clés.

Comment migrer de SharedPreferences vers DataStore

Google fournit un mécanisme de migration intégré via la classe SharedPreferencesMigration. La migration est effectuée une fois au premier démarrage après la mise à jour de l'application : DataStore lit les données de SharedPreferences, les écrit dans son propre format et marque la migration comme terminée.

La migration prend en charge les transformations personnalisées : si les clés dans SharedPreferences ne correspondent pas aux clés souhaitées de DataStore, vous pouvez spécifier une fonction de transformation via SharedPreferencesMigration. Cela permet de renommer les clés et de modifier les types de données pendant la migration.

Migration étape par étape

Premièrement, ajoutez DataStore à build.gradle et créez une instance DataStore avec migration : SharedPreferencesMigration accepte le nom du fichier SharedPreferences et un ensemble de clés à transférer. Deuxièmement, supprimez tout le code fonctionnant via SharedPreferences et remplacez-le par des appels DataStore. Troisièmement, testez la migration : au premier démarrage, les données doivent apparaître dans DataStore et l'ancien fichier SharedPreferences ne doit plus être utilisé.

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

Exemples d'utilisation de DataStore dans le code

DataStore s'intègre facilement dans un projet existant. Voici des exemples pratiques pour Preferences DataStore et Proto DataStore — tous deux démontrent la lecture, l'écriture et l'observation réactive des données.

Preferences DataStore : Lecture et écriture des paramètres

Dans cet exemple, Preferences DataStore stocke trois paramètres : le thème sombre, le nom d'utilisateur et le compteur de lancements. La lecture se fait via l'extension .data, qui retourne un Flow. L'écriture se fait via la fonction suspend .edit, qui garantit l'atomicité des modifications.

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 et utilisation

Proto DataStore nécessite la définition d'un fichier .proto. Après compilation, une classe UserSettings est créée et utilisée pour la lecture et l'écriture. Les migrations de version du schéma sont décrites dans le même fichier .proto et appliquées automatiquement.

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

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

// Lecture depuis DataStore
val userPreferencesFlow: Flow<UserPreferences> =
    protoDataStore.data

// Écriture de nouvelles valeurs
suspend fun updateDisplayName(name: String) {
    protoDataStore.updateData { prefs ->
        prefs.toBuilder()
            .setDisplayName(name)
            .build()
    }
}

Observation réactive des modifications

DataStore s'intègre avec l'architecture MVVM via ViewModel. Le Flow de DataStore est collecté via .stateIn et utilisé dans l'interface utilisateur. À chaque modification de données, l'interface utilisateur se met à jour automatiquement — aucune mise à jour manuelle ou LiveData n'est nécessaire.

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

Questions Fréquentes

En quoi DataStore est-il meilleur que SharedPreferences ?

DataStore fonctionne de manière asynchrone (ne bloque pas le thread UI), prend en charge l'accès concurrent via des transactions et permet l'abonnement réactif aux changements via Flow. SharedPreferences est une API synchrone avec un risque d'ANR avec de gros volumes de données et sans support réactif intégré.

Peut-on utiliser DataStore avec Java ?

DataStore est écrit en Kotlin et nécessite Kotlin Coroutines. L'utiliser depuis Java est possible mais peu pratique : il faudrait créer des wrappers avec CompletableFuture ou gérer manuellement les coroutines. Pour les projets Java, Google recommande de conserver SharedPreferences ou d'ajouter Kotlin au module.

DataStore est-il adapté au stockage de gros volumes de données ?

DataStore charge l'intégralité du fichier en mémoire lors de la lecture, il n'est donc pas adapté au stockage de listes ou d'objets volumineux. Pour de tels scénarios, utilisez Room ou SQLite. DataStore est optimisé pour les paramètres et les petites données structurées — jusqu'à des centaines de kilo-octets.

Comment gérer une erreur de fichier DataStore corrompu ?

Lors de la création d'un DataStore, vous pouvez passer un corruptionHandler — une fonction appelée lorsque le fichier est corrompu. Par défaut, DataStore lève une exception CorruptionException. Dans le corruptionHandler, vous pouvez retourner des données vides, après quoi DataStore réécrira le fichier dans un état correct.

Proto DataStore nécessite-t-il un fichier .proto ?

Oui, Proto DataStore nécessite la définition d'un schéma dans un fichier .proto et la connexion du protobuf-gradle-plugin. Si le projet est petit et les données simples, il est plus facile d'utiliser Preferences DataStore — il ne nécessite pas de configuration de build supplémentaire.

Résumé

  • DataStore — un remplacement moderne de SharedPreferences, fonctionnant avec Kotlin Coroutines et Flow
  • Preferences DataStore — simple clé-valeur sans schéma, adapté aux paramètres
  • Proto DataStore — stockage typé avec schéma protobuf et auto-migration
  • Migration depuis SharedPreferences est intégrée dans DataStore via SharedPreferencesMigration
  • Sécurité des threads — toutes les opérations sont asynchrones, le blocage de l'UI est éliminé
  • Réactivité — Flow notifie les abonnés à chaque modification de données
  • Recommandation — utilisez DataStore dans tous les nouveaux projets Android, migrez les existants lors du travail avec les paramètres

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi