DataStore的使用:

DataStore 是 Google 官方替代 SharedPreferences 的轻量本地存储方案,基于Kotlin 协程 + Flow ,全异步、非阻塞、线程安全、事务安全、无数据损坏、编译期类型安全,专门用于存储少量键值数据、配置信息、简单对象。

一、DataStore 核心基础

1. 为什么淘汰 SharedPreferences(SP)

SP 原生痛点全部被解决:

  • SP 主线程阻塞、apply() 会隐性卡顿、易 ANR;DataStore 纯协程异步,绝不阻塞主线程
  • SP 并发写入易数据丢失、文件损坏 ;DataStore 基于事务原子操作,崩溃也不会脏数据
  • SP 无编译期类型安全,运行时易 ClassCastException;DataStore 强类型 Key,编译报错拦截问题
  • SP 仅支持基础类型,不支持自定义对象、集合;Proto DataStore 支持任意结构化数据
  • SP 监听回调缺陷多;DataStore 基于 Flow,数据变化自动流通知,生命周期安全

2. DataStore 两种实现(必懂)

Google 提供两套 API,适配不同业务场景,日常开发优先用 Preferences DataStore,复杂对象用 Proto DataStore

表格

类型 特点 适用场景 数据格式
Preferences DataStore 类 SP 键值对、无需定义数据结构、上手快、基础类型全覆盖 用户配置、开关、简单键值、SP 迁移 键值对(String/Int/Boolean/Long/Float/Double)
Proto DataStore Protobuf 序列化、强类型安全、支持自定义实体 / 枚举 / 列表、结构数据 复杂对象、业务数据、需要类型严格校验 Protobuf 序列化自定义对象

3. 核心原理

  1. 底层基于文件存储,单文件写入,独占锁保证并发安全
  2. 全部 API 基于协程 + Flow ,无同步阻塞方法,所有读写都在后台线程
  3. 写入采用原子事务:先写入临时文件,成功后替换原文件,崩溃不损坏原数据
  4. 单例实例管理,全局唯一,避免多实例文件冲突

二、环境配置(最新稳定版 1.1.7,2026)

在 module 级 build.gradle.kts(app 模块)添加依赖

1. Preferences DataStore(键值版,最常用)

kotlin

scss 复制代码
// Preferences DataStore(替代SP)
implementation("androidx.datastore:datastore-preferences:1.1.7")
// 可选:RxJava 兼容(不用协程时用)
// implementation("androidx.datastore:datastore-preferences-rxjava3:1.1.7")

2. Proto DataStore(对象版)额外依赖

kotlin

scss 复制代码
// 基础DataStore核心
implementation("androidx.datastore:datastore:1.1.7")
// protobuf 插件配置(项目根目录build.gradle.kts)
plugins {
    id("com.google.protobuf") version "0.9.4" apply false
}
// app模块再引入插件
plugins {
    id("com.google.protobuf")
}

三、Preferences DataStore 完整实战(类 SP,最全代码)

日常 90% 场景用这个,和 SP 使用逻辑对齐,迁移零成本。

1. 定义 DataStore 单例(全局唯一)

建议写在 Application 扩展、工具类、单例类 ,全局只初始化一次,用 Context 扩展属性最优雅。

kotlin

kotlin 复制代码
import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStore

// Context 扩展属性,全局单例DataStore
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(
    name = "app_preferences" // 存储文件名,无需后缀,自动生成文件
)

// 封装工具类,外部直接调用,不用管Context
object DataStorePrefUtils {

    // 1. 定义所有Key(编译期类型安全,泛型指定类型,不会类型错乱)
    // 布尔型:开关
    val IS_LOGIN = booleanPreferencesKey("is_login")
    // 字符串:用户ID
    val USER_ID = stringPreferencesKey("user_id")
    // 整型:年龄
    val USER_AGE = intPreferencesKey("user_age")
    // 长整型:时间戳
    val LAST_LOGIN_TIME = longPreferencesKey("last_login_time")
    // 浮点型
    val USER_HEIGHT = floatPreferencesKey("user_height")
    // 双精度
    val USER_WEIGHT = doublePreferencesKey("user_weight")

    // 获取全局dataStore实例(需要传入Application Context,避免内存泄漏)
    private lateinit var dataStore: DataStore<Preferences>
    fun init(context: Context) {
        dataStore = context.dataStore
    }

    // ====================== 数据存储(协程写入)======================
    /**
     * 单个key写入
     */
    suspend fun <T> put(key: Preferences.Key<T>, value: T) {
        dataStore.edit { preferences ->
            preferences[key] = value
        }
    }

    /**
     * 批量写入(一次编辑多个key,效率更高)
     */
    suspend fun putAll(block: Preferences.Editor.() -> Unit) {
        dataStore.edit(block)
    }

    // ====================== 数据读取(Flow流,自动监听数据变化)======================
    /**
     * 读取单个key,返回Flow,数据变化自动回调
     * @param key 键
     * @param defaultValue 默认值(防止null)
     */
    fun <T> get(key: Preferences.Key<T>, defaultValue: T): Flow<T> {
        return dataStore.data
            .catch {
                // 异常捕获:文件损坏、读取异常
                emit(emptyPreferences())
            }
            .map { preferences ->
                preferences[key] ?: defaultValue
            }
    }

    // ====================== 删除、清空 ======================
    // 删除单个key
    suspend fun <T> remove(key: Preferences.Key<T>) {
        dataStore.edit {
            it.remove(key)
        }
    }

    // 清空所有数据
    suspend fun clear() {
        dataStore.edit {
            it.clear()
        }
    }
}

2. 初始化(Application 中)

必须用 Application 上下文,不能用 Activity 上下文,防止内存泄漏

kotlin

kotlin 复制代码
class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        // 初始化DataStore工具类
        DataStorePrefUtils.init(this)
    }
}

清单文件注册 Application

xml

ini 复制代码
<application
    android:name=".MyApp"
    ...>
</application>

3. Activity/Fragment 中使用(协程环境)

DataStore 所有读写必须在协程作用域 (lifecycleScope、viewModelScope),禁止主线程直接调用挂起函数。

3.1 写入数据(挂起函数)

kotlin

kotlin 复制代码
// 方式1:单个写入
lifecycleScope.launch {
    DataStorePrefUtils.put(DataStorePrefUtils.IS_LOGIN, true)
    DataStorePrefUtils.put(DataStorePrefUtils.USER_ID, "10086")
}

// 方式2:批量写入(推荐,一次事务,性能更好)
lifecycleScope.launch {
    DataStorePrefUtils.putAll {
        this[IS_LOGIN] = true
        this[USER_ID] = "10086"
        this[USER_AGE] = 25
        this[LAST_LOGIN_TIME] = System.currentTimeMillis()
    }
}

3.2 读取数据(Flow 流式读取,监听数据实时变化)

kotlin

kotlin 复制代码
// 读取并监听:只要存储值改变,这里自动收到新值
lifecycleScope.launch {
    DataStorePrefUtils.get(DataStorePrefUtils.IS_LOGIN, false)
        .collect { isLogin ->
            // 每次数据变化都会回调
            Log.d("DataStore", "登录状态:$isLogin")
        }
}

// 读取单次数据(只拿当前值,不持续监听)
lifecycleScope.launch {
    val userId = DataStorePrefUtils.get(DataStorePrefUtils.USER_ID, "").first()
    Log.d("DataStore", "用户ID:$userId")
}

3.3 删除、清空

kotlin

csharp 复制代码
lifecycleScope.launch {
    // 删除单个key
    DataStorePrefUtils.remove(DataStorePrefUtils.USER_AGE)
    // 清空全部
    // DataStorePrefUtils.clear()
}

4. ViewModel 中使用(最规范写法)

viewModelScope 生命周期绑定 ViewModel,自动管理协程,无需手动取消

kotlin

kotlin 复制代码
class MainViewModel : ViewModel() {

    // 存储数据
    fun saveData() {
        viewModelScope.launch {
            DataStorePrefUtils.put(DataStorePrefUtils.IS_LOGIN, true)
        }
    }

    // 暴露Flow给UI观察(Compose/Flow布局直接收集)
    val loginStateFlow: Flow<Boolean> = DataStorePrefUtils.get(DataStorePrefUtils.IS_LOGIN, false)
}

四、SharedPreferences 一键迁移(官方 API,无痛迁移)

老项目全部 SP 数据,一行代码自动迁移到 DataStore,无需手动遍历键值。

Preferences DataStore 迁移改造

只需要在初始化时添加 migrations 参数

kotlin

ini 复制代码
import androidx.datastore.preferences.core.migrations
import androidx.datastore.preferences.migrateSharedPreferences

private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(
    name = "app_preferences",
    // 迁移配置:原SP文件名 + 自动迁移所有键值
    migrations = listOf(
        migrateSharedPreferences(sharedPreferencesName = "sp_config")
    )
)
  • sp_config:你原来 SP 的文件名(getSharedPreferences("sp_config",MODE_PRIVATE))
  • 原理:首次启动 DataStore 时,自动读取全部 SP 数据写入 DataStore,之后不再读取 SP,完全无缝切换。

五、Proto DataStore 完整实战

等待研究....

相关推荐
hai_android28 分钟前
InputStage 责任链核心执行流程
android·android studio·android jetpack
传奇开心果编程1 天前
【现代声明式UI学与练】第4课 列表渲染与 key——如何高效渲染列表、key 的作用、列表重排时的状态保持
学习·flutter·react native·ui·swiftui·android jetpack
传奇开心果编程2 天前
【现代声明式UI学与练】第7课 组件通信——父传子、子传父、跨层级通信、状态提升与 Context
学习·flutter·react native·ui·swiftui·android jetpack
传奇开心果编程2 天前
【现代声明式UI学与练】第9课 性能优化——渲染优化、列表优化、内存优化、启动优化
学习·flutter·react native·ui·性能优化·swiftui·android jetpack
天空之城--4 天前
Android一周动态:Android 18首次官宣、Compose Material3 1.4转正(5趋势+5资讯)
android·人工智能·flutter·架构·android jetpack
传奇开心果编程5 天前
【现代声明式UI学与练】第1课 从命令式UI到声明式UI
学习·flutter·ui·swiftui·react·android jetpack
传奇开心果编程8 天前
【用案例学Material 3 Expressive】第1课:从一封邮件开始,感受安卓设计新语言的表现力
android·学习·ui·kotlin·android jetpack
传奇开心果编程9 天前
【Jetpack Compose进阶学与练】第14课:系列收尾复习总结;Compose项目常见坑点汇总;学习路线与后续学习方向
android·学习·ui·kotlin·android jetpack
hai_android9 天前
子 View 被压小时,如何向父容器"告状"?——MEASURED_STATE_TOO_SMALL 向上传递机制
android·kotlin·android jetpack
alexhilton10 天前
生命周期感知的多模块启动模式
android·kotlin·android jetpack