摘要:在Android开发的浩瀚宇宙中,数据存储始终是一个绕不开的话题。从最初的SharedPreferences到如今炙手可热的DataStore,每一次技术的迭代都旨在让开发者的生活更加轻松,也让用户的应用体验更加流畅。今天,我们就来聊聊DataStore是如何
在Android开发的浩瀚宇宙中,数据存储始终是一个绕不开的话题。从最初的SharedPreferences到如今炙手可热的DataStore,每一次技术的迭代都旨在让开发者的生活更加轻松,也让用户的应用体验更加流畅。今天,我们就来聊聊DataStore是如何在Android开发中优雅替代SharedPreferences的。
在DataStore横空出世之前,SharedPreferences一直是Android开发者存储轻量级数据的首选。然而,随着应用功能的日益复杂,SharedPreferences的局限性也逐渐暴露出来:
同步阻塞:SharedPreferences的get方法是同步的,这意味着在主线程上读取数据可能会导致UI卡顿,影响用户体验。而apply方法虽然异步,但在某些情况下仍可能引发ANR(应用无响应)问题。类型安全缺失:SharedPreferences在存储和读取数据时,缺乏类型检查,容易导致ClassCastexception等运行时异常。事务处理不足:SharedPreferences不支持原子操作,多个写操作之间可能会相互干扰,导致数据不一致。面对SharedPreferences的种种不足,DataStore应运而生。作为Android Jetpack组件库中的新成员,dataStore以其异步、一致的事务处理方式和强大的类型安全特性,迅速赢得了开发者的青睐。
异步操作,告别卡顿:DataStore使用Kotlin协程和Flow实现异步操作,读写数据不再阻塞主线程,让应用更加流畅。类型安全,减少错误:DataStore支持使用Protocol Buffers定义数据模型,确保在编译时进行类型检查,减少因类型不匹配导致的运行时错误。事务处理,数据一致:DataStore以事务方式处理数据更新,保证数据的一致性和完整性,即使在发生错误时也能保持数据的状态。DataStore提供了两种主要的实现方式:Preferences DataStore和Proto DataStore,分别适用于不同的场景。
Preferences DataStore:适用于存储简单的键值对数据,如用户设置、应用状态等。它提供了与SharedPreferences类似的API,但更加健壮和类型安全。添加依赖:在build.gradle文件中添加implementation "androidx.datastore:datastore-preferences:1.1.1"。创建DataStore实例:使用preferencesDataStore属性委托来创建Preferences DataStore实例。定义数据键值:使用Google提供的方法(如intPreferencesKey、stringPreferencesKey等)来定义键值。存储和读取数据:通过协程和Flow来异步地存储和读取数据。Proto DataStore:适用于存储复杂的数据结构,如用户游戏存档、购物车信息等。它使用Protocol Buffers定义数据模型,支持存储自定义数据类型。定义proto结构:在app/src/main/proto/目录下创建proto文件,定义数据模型。生成Java类:通过编译生成对应的Java类。实现序列化器:定义一个实现Serializer接口的类,用于序列化和反序列化数据。创建DataStore实例:使用生成的序列化器来创建Proto DataStore实例。操作数据:通过协程和Flow来异步地操作数据。DataStore适用于需要存储轻量级数据且对类型安全和异步操作有较高要求的场景。例如:
用户设置:存储用户的个性化设置,如夜间模式、字体大小等。应用状态:缓存接口返回的简单数据,保存应用状态(如表单草稿)。跨进程共享数据:在需要跨进程共享数据的场景下,DataStore提供了更好的支持。然而,对于需要存储大量结构化数据(如用户游戏存档、购物车信息等)的场景,或者需要存储图片、视频等大型文件的场景,DataStore可能不是最佳选择。此时,可以考虑使用Room数据库或直接使用文件存储。
对于已经使用SharedPreferences的应用,迁移到DataStore需要做一些改动。主要包括:
声明DataStore对象:在Application类中初始化DataStore实例。定义key和value类型:根据需求定义好要存储的键值对或复杂数据结构。使用协程和Flow进行数据存储和读取:将原有的SharedPreferences操作替换为DataStore的异步操作。迁移老数据:使用DataStore提供的迁移方法(如dataStore.migrateFrom(sharedPrefs))一键迁移老数据。implementation "androidx.datastore:datastore-preferences:1.0.0"基本使用// 创建 DataStore 实例val Context.dataStore by preferencesDataStore(name = "settings")// 写入数据suspend fun saveUserPreference(context: Context, username: String, token: String) {context.dataStore.edit { preferences ->preferences[PreferencesKeys.USERNAME] = usernamepreferences[PreferencesKeys.TOKEN] = token}}// 读取数据val Context.usernameFlow: Flow get = dataStore.data.map { preferences ->preferences[PreferencesKeys.USERNAME] ?: "default"}// 定义键object PreferencesKeys {val USERNAME = stringPreferencesKey("username")val TOKEN = stringPreferencesKey("token")}implementation "androidx.datastore:datastore-core:1.0.0"implementation "androidx.datastore:datastore:1.0.0"定义数据结构(proto文件)syntax = "proto3";option java_package = "com.example.app";option java_multiple_files = true;message UserPreferences {string username = 1;int32 age = 2;bool is_dark_theme = 3;}使用// 创建 DataStore 实例private val Context.userPreferencesStore by protoDataStore(fileName = "user_preferences.pb",serializer = UserPreferencesSerializer)// 写入数据suspend fun updateAge(context: Context, newAge: Int) {context.userPreferencesStore.updateData { preferences ->preferences.toBuilder.setAge(newAge).build}}// 读取数据val Context.userPreferencesFlow: Flow get = userPreferencesStore.data// 序列化器实现object UserPreferencesSerializer : Serializer {override val defaultValue: UserPreferences = UserPreferences.getDefaultInstanceoverride suspend fun readFrom(input: InputStream): UserPreferences {try {return UserPreferences.parseFrom(input)} catch (Exception: InvalidProtocolBufferException) {throw CorruptionException("Cannot read proto.", exception)}}override suspend fun writeTo(t: UserPreferences, output: OutputStream) {t.writeTo(output)}}class SettingsViewModel(context: Context) : ViewModel {private val dataStore = context.applicationContext.dataStoreval usernameFlow: Flow = dataStore.data.map { preferences ->preferences[PreferencesKeys.USERNAME] ?: "default"}suspend fun updateUsername(newUsername: String) {dataStore.edit { preferences ->preferences[PreferencesKeys.USERNAME] = newUsername}}}DataStore 提供了比 SharedPreferences 更强大和灵活的数据存储方案,特别适合现代 Android 应用开发。
DataStore作为Android官方推荐的新一代数据存储方案,以其异步、一致的事务处理方式和强大的类型安全特性,为开发者提供了更加便捷、高效的数据存储体验。在未来的Android开发中,DataStore有望成为轻量级数据存储的首选方案。如果你还在为SharedPreferences的种种不足而烦恼,不妨尝试一下DataStore吧!相信它会给你带来意想不到的惊喜。
来源:小萱科技每日一讲