DataStore: qué es, fundamentos de almacenamiento de datos y reemplazo de SharedPreferences

Autor: IT Sectr Publicado: 2026-03-12 Tiempo de lectura: 9 min

DataStore es un componente de la librería Jetpack diseñado para almacenar pequeñas cantidades de datos en aplicaciones Android. A diferencia de SharedPreferences, funciona de forma asíncrona y garantiza la consistencia de los datos bajo acceso concurrente. Según Google, 2024, DataStore usa Kotlin Coroutines y Flow, lo que lo hace seguro para el hilo principal y adecuado para arquitecturas reactivas.

Puntos Clave

  • DataStore — un reemplazo para SharedPreferences con API asíncrona y tipos de datos mediante Protocol Buffers
  • Preferences DataStore — un almacén simple clave-valor con lectura mediante Flow y transacciones
  • Proto DataStore — un almacenamiento tipado con migraciones de esquema automáticas
  • SharedPreferences — API síncrona que bloquea el hilo UI con grandes volúmenes
  • Migración se realiza a través de la interfaz SharedPreferencesMigration sin pérdida de datos

¿Qué es DataStore?

DataStore es una solución de Google para el almacenamiento local de datos en Android, presentada en 2020 como alternativa a SharedPreferences. Soporta dos modos: Preferences DataStore (pares simples clave-valor) y Proto DataStore (esquema tipado basado en Protocol Buffers).

La principal ventaja es la asincronía total: todas las operaciones de lectura devuelven un Flow de Kotlin Coroutines, y las escrituras se realizan en un contexto de corrutina. Esto elimina el bloqueo del hilo principal, que era un problema típico de SharedPreferences al manejar grandes volúmenes de datos.

DataStore garantiza la atomicidad de las operaciones: las escrituras concurrentes no provocan pérdida de datos gracias a su modelo transaccional. Si dos componentes modifican el mismo valor simultáneamente, DataStore maneja correctamente el conflicto mediante un mecanismo de compare-and-swap.

Según Google I/O 2023, DataStore se usa en el 40% de los nuevos proyectos Android, y Google recomienda migrar desde SharedPreferences en todas las aplicaciones donde se requiera estabilidad en el almacenamiento de configuraciones.

Arquitectura de DataStore

En el núcleo de DataStore se encuentra SingleProcessDataStore — una implementación que opera dentro de un solo proceso. Utiliza almacenamiento basado en archivos con bloqueo a nivel de archivo: al escribir datos, el archivo se bloquea, evitando la corrupción bajo acceso concurrente.

DataStore maneja automáticamente los errores de deserialización: si el archivo está dañado, devuelve un valor por defecto y sobrescribe el archivo. Este comportamiento es configurable mediante corruptionHandler, que se puede establecer al crear el DataStore.

Problemas de SharedPreferences que DataStore resuelve

SharedPreferences sufre de tres problemas fundamentales: lectura síncrona del disco en el hilo principal, falta de garantías de atomicidad para escrituras concurrentes e imposibilidad de rastrear cambios de forma reactiva. DataStore resuelve los tres: Flow para observación, bloqueo de archivos para atomicidad y API asíncrona para seguridad de hilos.

¿Cómo funciona DataStore en Android?

DataStore almacena datos en archivos en el almacenamiento interno del dispositivo. Preferences DataStore usa un formato de archivo similar a SharedPreferences pero con metadatos adicionales para verificación de integridad. Proto DataStore usa el formato binario Protocol Buffers, lo que reduce el tamaño del archivo y acelera la serialización.

Al leer datos, DataStore carga todo el archivo en memoria una vez, tras lo cual los suscriptores reciben el estado actual mediante Flow. Los cambios se transmiten a todos los suscriptores activos automáticamente — no se requiere registro manual de listeners, como en SharedPreferences.

Cómo funciona Preferences DataStore

Preferences DataStore utiliza un mecanismo de serialización incorporado basado en un Map. Cada entrada es un par de una cadena y un tipo primitivo (Int, Boolean, Float, Long, String, Set). Los datos se almacenan en un archivo XML, similar a SharedPreferences, pero con escritura atómica mediante bloqueo de archivos.

Ejemplo de creación de Preferences DataStore: la extensión preferencesDataStore en Context crea un singleton con el nombre del archivo. En llamadas repetidas, se devuelve la misma instancia — esto elimina la duplicación de archivos y la confusión entre diferentes instancias de almacenamiento.

Cómo funciona Proto DataStore

Proto DataStore requiere definir un esquema de datos mediante un archivo .proto y compilarlo con el plugin protobuf. La clase Java generada se usa como único punto de entrada para todos los campos — esto elimina errores tipográficos en las claves, comunes con SharedPreferences.

El esquema de Proto DataStore se define una vez y soporta la adición de nuevos campos sin perder datos antiguos. Si una nueva versión de la aplicación añade un campo con un valor por defecto, el archivo antiguo se deserializará correctamente — la compatibilidad hacia atrás está integrada en el protocolo.

Preferences DataStore vs Proto DataStore: Comparación

La elección entre Preferences DataStore y Proto DataStore depende de la complejidad de los datos y los requisitos de tipificación. Ambas opciones son asíncronas y transaccionales, pero difieren en seguridad de tipos y rendimiento de serialización.

CaracterísticaPreferences DataStoreProto DataStore
TipificaciónDébil (clave-valor)Fuerte (clase generada)
SerializaciónXML (incorporada)Protocol Buffers (protobuf)
Tamaño de archivoGrande (XML legible)Pequeño (binario)
ComplejidadBaja (sin .proto)Media (requiere .proto)
Migración de esquemaSin esquemaAutomática (proto)
CompatibilidadSharedPreferences (vía migración)Solo Proto DataStore

Cuándo elegir Preferences DataStore

Preferences DataStore es adecuado para configuraciones simples: banderas de funciones, cadena de token de autorización, número de inicios de la aplicación. Si los datos son pocos (hasta 10–15 claves) y no requieren un esquema estricto, Preferences DataStore proporciona un umbral de entrada mínimo sin conectar el plugin protobuf.

Cuándo elegir Proto DataStore

Proto DataStore se justifica cuando la estructura de datos es compleja o puede cambiar entre versiones de la aplicación. Por ejemplo, configuración de perfil de usuario o configuración de pruebas A/B con 20+ campos. Protobuf proporciona tipificación fuerte y migraciones automáticas, eliminando errores en tiempo de ejecución por discrepancias de claves.

Cómo migrar de SharedPreferences a DataStore

Google proporciona un mecanismo de migración incorporado a través de la clase SharedPreferencesMigration. La migración se realiza una vez en el primer inicio después de la actualización de la aplicación: DataStore lee los datos de SharedPreferences, los escribe en su propio formato y marca la migración como completada.

La migración soporta transformaciones personalizadas: si las claves en SharedPreferences no coinciden con las claves deseadas de DataStore, se puede especificar una función de transformación mediante SharedPreferencesMigration. Esto permite renombrar claves y cambiar tipos de datos durante la migración.

Migración paso a paso

Primero, añade DataStore a build.gradle y crea una instancia de DataStore con migración: SharedPreferencesMigration acepta el nombre del archivo SharedPreferences y un conjunto de claves a transferir. Segundo, elimina todo el código que funcione con SharedPreferences y reemplázalo con llamadas a DataStore. Tercero, prueba la migración: en el primer inicio, los datos deberían aparecer en DataStore y el archivo SharedPreferences antiguo ya no debería usarse.

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

Ejemplos de uso de DataStore en código

DataStore se integra fácilmente en un proyecto existente. A continuación se muestran ejemplos prácticos para Preferences DataStore y Proto DataStore — ambos demuestran lectura, escritura y observación reactiva de datos.

Preferences DataStore: Lectura y escritura de configuraciones

En este ejemplo, Preferences DataStore almacena tres configuraciones: tema oscuro, nombre de usuario y contador de inicios. La lectura se realiza mediante la extensión .data, que devuelve un Flow. La escritura se realiza mediante la función suspend .edit, que garantiza la atomicidad de los cambios.

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: Esquema y uso

Proto DataStore requiere definir un archivo .proto. Después de la compilación, se crea una clase UserSettings que se utiliza para lectura y escritura. Las migraciones de versión del esquema se describen en el mismo archivo .proto y se aplican automáticamente.

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

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

// Lectura desde DataStore
val userPreferencesFlow: Flow<UserPreferences> =
    protoDataStore.data

// Escritura de nuevos valores
suspend fun updateDisplayName(name: String) {
    protoDataStore.updateData { prefs ->
        prefs.toBuilder()
            .setDisplayName(name)
            .build()
    }
}

Observación reactiva de cambios

DataStore se integra con la arquitectura MVVM a través de ViewModel. El Flow de DataStore se recoge mediante .stateIn y se usa en la UI. Con cada cambio de datos, la UI se actualiza automáticamente — no se necesitan actualizaciones manuales ni 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()
            )
}

Preguntas Frecuentes

¿En qué es mejor DataStore que SharedPreferences?

DataStore funciona de forma asíncrona (no bloquea el hilo UI), soporta acceso concurrente mediante transacciones y permite la suscripción reactiva a cambios a través de Flow. SharedPreferences es una API síncrona con riesgo de ANR con grandes volúmenes de datos y sin soporte integrado de reactividad.

¿Se puede usar DataStore con Java?

DataStore está escrito en Kotlin y requiere Kotlin Coroutines. Usarlo desde Java es posible pero incómodo: habría que crear envoltorios con CompletableFuture o gestionar las corrutinas manualmente. Para proyectos Java, Google recomienda mantener SharedPreferences o añadir Kotlin al módulo.

¿Es DataStore adecuado para almacenar grandes cantidades de datos?

DataStore carga todo el archivo en memoria al leer, por lo que no es adecuado para almacenar listas u objetos grandes. Para tales escenarios, usa Room o SQLite. DataStore está optimizado para configuraciones y datos estructurados pequeños — hasta cientos de kilobytes.

¿Cómo manejar un error de archivo DataStore dañado?

Al crear un DataStore, puedes pasar un corruptionHandler — una función que se llama cuando el archivo está dañado. Por defecto, DataStore lanza una excepción CorruptionException. En el corruptionHandler, puedes devolver datos vacíos, tras lo cual DataStore sobrescribirá el archivo con un estado correcto.

¿Proto DataStore requiere un archivo .proto?

Sí, Proto DataStore requiere definir un esquema en un archivo .proto y conectar el protobuf-gradle-plugin. Si el proyecto es pequeño y los datos son simples, es más fácil usar Preferences DataStore — no requiere configuración adicional de compilación.

Resumen

  • DataStore — un reemplazo moderno para SharedPreferences, que funciona con Kotlin Coroutines y Flow
  • Preferences DataStore — simple clave-valor sin esquema, adecuado para configuraciones
  • Proto DataStore — almacenamiento tipado con esquema protobuf y auto-migración
  • Migración desde SharedPreferences está integrada en DataStore mediante SharedPreferencesMigration
  • Seguridad de hilos — todas las operaciones son asíncronas, se elimina el bloqueo de la UI
  • Reactividad — Flow notifica a los suscriptores en cada cambio de datos
  • Recomendación — usa DataStore en todos los proyectos nuevos de Android, migra los existentes al trabajar con configuraciones

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también