现在可以开始将 SharedPreferences 迁移到 Preferences DataStore 了。因为 DataStore 的存在就是为了替代SP,所以谷歌早提供SharedPreferencesMigration属性用于SP数据迁移。其他代码与前面类似,只需向迁移列表传入 SharedPreferencesMigration属性,其中构造函数第二个参数 sharedPreferencesName 为所创建SP的文件名称,在本例中即为”test“。

private val Context.dataStore: DataStore by preferencesDataStore(
name = “preferences-test”,
// 新增部分
produceMigrations = { context ->
listOf(SharedPreferencesMigration(context, “test”))
}
)

由于键只能从 SharedPreferences 迁移一次,因此在我们迁移完毕后,需要将刚才临时创建的SP相关代码删除,此时的完整代码如下:
有一处需要注意的,在SP文件创建时,我们的key值设置为“number”,迁移后dataStore的key值也会被设置为“number”。所以与前面的例子相比,我们还需要将intPreferencesKey()函数中的key值更改为“number”。

class MainActivity : AppCompatActivity() {

// 创建:preferencesDataStore 委托可确保我们有一个 DataStore 实例在应用中具有该名称
private val Context.dataStore: DataStore by preferencesDataStore(
name = “preferences-test”,
produceMigrations = { context ->
listOf(SharedPreferencesMigration(context, “test”))
}
)
private val COUNTER = intPreferencesKey(“number”)

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

val tv = findViewById(R.id.tv_test)
val fab = findViewById(R.id.fab)

MainScope().launch {
dataStore.data
.map {
it[COUNTER] ?: 0
}.collect {
tv.text = it.toString()
}
}
fab.setOnClickListener {
MainScope().launch {
dataStore.edit {
val currentCounterValue = it[COUNTER] ?: 0
it[COUNTER] = currentCounterValue + 1
}
}
}
}
}

运行程序后可以看到界面初始数值为10,说明迁移完毕

Proto DataStore

SharedPreferences 和 Preferences DataStore 的一个缺点是无法定义架构,保证不了存取键时使用了正确的数据类型。而 Proto DataStore 利用协议缓冲区来定义架构来解决此问题,确保了类型安全。 协议缓冲区可持久保留强类型数据。与 XML 和其他类似的数据格式相比,协议缓冲区速度更快、规格更小、使用更简单,并且更清楚明了。虽然使用 Proto DataStore 需要学习新的序列化机制,但因为 Proto DataStore 的强大类型优势,所以非常值得我们学习。

添加依赖
  1. 添加协议缓冲区插件

plugins {
……
id “com.google.protobuf” version “0.8.17”
}

  1. 添加协议缓冲区和 Proto DataStore 依赖项

dependencies {
……
implementation “androidx.datastore:datastore:1.0.0”
implementation “com.google.protobuf:protobuf-javalite:3.18.0”
}

  1. 配置协议缓冲区
    如果在这步Sync Now报错,先Sync Now前两步再Sync Now对协议缓冲区的配置

protobuf {
protoc{
// 设置 protoc 的版本号
artifact = “com.google.protobuf:protoc:3.14.0”
}
generateProtoTasks {
all().each { task ->
task.builtins {
java {
option ‘lite’
}
}
}
}
}

定义架构

在 app/src/main/ 目录下创建proto文件夹,我们将在里面创建proto文件,如图所示

创建count.proto文件,文件和相关注释内容如下:
其中内部类字段类型与Java的对应关系:
string->String,int32->int,int64->long,bool->Boolean,float->float,double->double

// 声明proto的版本
syntax = “proto3”;

option java_package = “com.wg.jetpackDemos.dataStore.proto”; // 指定了生成的Java类的包名
option java_multiple_files = true; // 设置生成的Java类是一个文件还是多个文件

// message 声明的是内部类
message Count {
int32 counter = 1;
}

每当我们创建或者变更proto文件时都需要Rebuild Project,即可生成对应的Java文件

创建 Proto DataStore
  1. 创建序列化器:
    定义一个实现 Serializer<T>的类,其中 T 是 proto 文件中定义的类型。通过实现序列化器告知DataStore如何读取和写入我们在 proto 文件中定义的数据类型,如果磁盘上没有数据,序列化器还会定义默认返回值。

object CountData : Serializer {
override val defaultValue: Count
get() = Count.getDefaultInstance()

override suspend fun readFrom(input: InputStream): Count {
try {
return Count.parseFrom(input)
}catch (exception:InvalidProtocolBufferException){
throw CorruptionException(“Cannot read proto.”, exception)
}
}

override suspend fun writeTo(t: Count, output: OutputStream)
= t.writeTo(output)
}

  1. 创建 Proto DataStore 实例
    使用 dataStore 所创建的属性委托来创建 DataStore<T> 实例,其中 T 是在 proto 文件中定义的类型。
    fileName参数:告知 DataStore 使用哪个文件存储数据
    serializer 参数:告知 DataStore 在第一步中定义的序列化器类的名称

val Context.counterDataStore : DataStore by dataStore(
fileName = “count.pb”,
serializer = CountData
)

写入数据

与Preferences DataStore不同,Proto DataStore使用updatData()函数用于更新存储的对象。

fab.setOnClickListener {
MainScope().launch {
counterDataStore.updateData { count ->
count.toBuilder()
.setCounter(count.counter + 1)
.build()
}
}
}

读取数据

读取数据则与 Preferences DataStore 类似

MainScope().launch {
counterDataStore.data.collect { count ->
tv.text = count.counter.toString()
}
}

从 SharedPreferences 迁移到 Proto DataStore

前期准备与上面“从 SharedPreferences 迁移到 Preferences DataStore”部分相同,如果有跳过 Preferences DataStore 部分直接看 Proto DataStore 的朋友需要往回翻看一下。
同迁移到 Preferences DataStore 的思路一样,我们只需在DataStore构造器中向迁移列表传入 SharedPreferencesMigration属性。这里需要注意的是,SharedPreferencesMigration的包为androidx.datastore.migrations.SharedPreferencesMigration,我那时候因为导错包找了好久的bug,请以我为戒。

val Context.counterDataStore : DataStore by dataStore(
fileName = “count.pb”,
serializer = CountData,
produceMigrations = { context ->
listOf(
SharedPreferencesMigration(context,“test”){
sharedPreferencesView, counter ->
// 获取 SharedPreferences 的数据
val count = sharedPreferencesView.getInt(“number”,0)
counter.toBuilder().setCounter(count).build()
}
)
}
)

在运行前记得删掉SP相关代码,迁移完毕结果如下:

Android 学习笔录

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数HarmonyOS鸿蒙开发工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年HarmonyOS鸿蒙开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
img

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

S鸿蒙开发知识点,真正体系化!**

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
[外链图片转存中…(img-TMfOrBzg-1712681775174)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

更多推荐