下面我们再写一个取数据的方法。
private fun get() = runBlocking {
return@runBlocking dataStore.data.map { it[key] ?: “新冠” }.first()
}
你会发现和存数据又有不同,这里的first()就是取值,这个方法换个方式来看就清晰一些。
然后我们在取数据按钮的点击事件中调用。
下面我们运行一下:
第一次我先取数据,显示的是默认值,然后我存数据再取数据。效果就是这样,但你会觉得使用起来很麻烦,不如SP好用,这个我们后面再去封装,先了解一些它的功能特性。
在进行定义dataStore时,会在手机中生成一个pb文件,这里我们用虚拟机来看,
然后通过你的程序包名去找
这里的文件就是存放你的缓存信息的文件。这里我用txt打开看一下
可以看到键和值,也许是浏览文件不对,下面我们清理一下这个数据。在布局中增加一个按钮
在代码中
通过clear方法调用进行数据的清除,清除后我们再看看这个pb文件
这个文件就什么都没有了,清除的干干净净。
这个DataStore是肯定需要封装之后再使用的,直接使用太麻烦了,我们需要封装的像SP那样好用,数据类型就参考这个方法中的数据类型。
在写封装代码之前呢,我们先创建一个App类,里面的代码如下:
class App : Application() {
companion object {
lateinit var instance : App
}
override fun onCreate() {
super.onCreate()
instance = this
}
}
然后我们在AndroidManifest中设置
下面我们新建一个EasyDataStore类,将它设置为object,先创建DataStore,代码如下:
// 创建DataStore
val App.dataStore: DataStore by preferencesDataStore(
name = “Study”
)
// DataStore变量
val dataStore = App.instance.dataStore
下面我们先写好各个数据类型的存取方法,先写存数据的方法:
/**
- 存放Int数据
*/
private suspend fun putIntData(key: String, value: Int) = dataStore.edit {
it[intPreferencesKey(key)] = value
}
/**
- 存放Long数据
*/
private suspend fun putLongData(key: String, value: Long) = dataStore.edit {
it[longPreferencesKey(key)] = value
}
/**
- 存放String数据
*/
private suspend fun putStringData(key: String, value: String) = dataStore.edit {
it[stringPreferencesKey(key)] = value
}
/**
- 存放Boolean数据
*/
private suspend fun putBooleanData(key: String, value: Boolean) = dataStore.edit {
it[booleanPreferencesKey(key)] = value
}
/**
- 存放Float数据
*/
private suspend fun putFloatData(key: String, value: Float) = dataStore.edit {
it[floatPreferencesKey(key)] = value
}
/**
- 存放Double数据
*/
private suspend fun putDoubleData(key: String, value: Double) = dataStore.edit {
it[doublePreferencesKey(key)] = value
}
然后是取数据的方法:
/**
- 取出Int数据
*/
private fun getIntData(key: String, default: Int = 0): Int = runBlocking {
return@runBlocking dataStore.data.map {
it[intPreferencesKey(key)] ?: default
}.first()
}
/**
- 取出Long数据
*/
private fun getLongData(key: String, default: Long = 0): Long = runBlocking {
return@runBlocking dataStore.data.map {
it[longPreferencesKey(key)] ?: default
}.first()
}
/**
- 取出String数据
*/
private fun getStringData(key: String, default: String? = null): String = runBlocking {
return@runBlocking dataStore.data.map {
it[stringPreferencesKey(key)] ?: default
}.first()!!
}
/**
- 取出Boolean数据
*/
private fun getBooleanData(key: String, default: Boolean = false): Boolean = runBlocking {
return@runBlocking dataStore.data.map {
it[booleanPreferencesKey(key)] ?: default
}.first()
}
/**
- 取出Float数据
*/
private fun getFloatData(key: String, default: Float = 0.0f): Float = runBlocking {
return@runBlocking dataStore.data.map {
it[floatPreferencesKey(key)] ?: default
}.first()
}
/**
- 取出Double数据
*/
private fun getDoubleData(key: String, default: Double = 0.00): Double = runBlocking {
return@runBlocking dataStore.data.map {
it[doublePreferencesKey(key)] ?: default
}.first()
}
最后我们根据存取的数据类型去做一个封装,存数据,代码如下:
/**
- 存数据
*/
fun putData(key: String, value: T) {
runBlocking {
when (value) {
is Int -> putIntData(key, value)
is Long -> putLongData(key, value)
is String -> putStringData(key, value)
is Boolean -> putBooleanData(key, value)
is Float -> putFloatData(key, value)
is Double -> putDoubleData(key, value)
else -> throw IllegalArgumentException(“This type cannot be saved to the Data Store”)
}
}
}
取数据:
/**
- 取数据
*/
fun getData(key: String, defaultValue: T): T {
val data = when (defaultValue) {
is Int -> getIntData(key, defaultValue)
is Long -> getLongData(key, defaultValue)
is String -> getStringData(key, defaultValue)
is Boolean -> getBooleanData(key, defaultValue)
is Float -> getFloatData(key, defaultValue)
is Double -> getDoubleData(key, defaultValue)
else -> throw IllegalArgumentException(“This type cannot be saved to the Data Store”)
}
return data as T
}
对了,还有一个清除数据的方法:
/**
- 清空数据
*/
fun clearData() = runBlocking { dataStore.edit { it.clear() } }
这样我们的DataStore就封装好了,下面我们在MainActivity中使用一下:
这里我们存数据、取数据、清空数据都用到了,下面运行一下:
对于DataStore最基本的操作就完成了,那么下面来进阶一下。
其实我们刚才使用的是Preferences DataStore,是对数据进行操作,下面要操作的是Proto DataStore,官网上的说法是Proto DataStore 将数据作为自定义数据类型的实例进行存储。此实现要求您使用协议缓冲区来定义架构,但可以确保类型安全。
Proto DataStore中采用的是ProtorBuffer,优势是性能好、效率高,表现在对数据的序列化和反序列化时间快,占用的空间小,还记得之前我们看到的那个pb文件吗,它里面采用的就是protobuf,之前一直是Google内部使用,这也是源于它的缺点,之前这个pb文件我们打开过,里面只能看懂键和值,缺乏描述,因此就影响了可读性,和广泛性,不如Json和XML简单。因此我们目前也只是在DataStore中使用protobuf,下面为了使用,我们需要在项目中装一个插件。
1. 插件安装
这个插件的安装比较的麻烦,首先是添加协议缓冲区插件
① 添加协议缓冲区插件
首先打开工程的build.gradle,在里面添加如下代码:
id “com.google.protobuf” version “0.8.12” apply false
再打开app下的build.gradle,添加如下代码:
id ‘com.google.protobuf’
② 添加协议缓冲区和 Proto DataStore 依赖项
在app的dependencies{}闭包中添加如下代码:
//Proto DataStore
implementation ‘androidx.datastore:datastore-core:1.0.0’
implementation ‘com.google.protobuf:protobuf-javalite:3.10.0’
③ 配置协议缓冲区
在app的build.gradle中添加如下代码:
protobuf {
protoc {
artifact = “com.google.protobuf:protoc:3.10.0”
}
// 为该项目中的 Protobufs 生成 java Protobuf-lite 代码。
generateProtoTasks {
all().each { task ->
task.builtins {
java {
option ‘lite’
}
}
}
}
}
注意它添加的位置:
点击Sync Now。
2. 创建proto文件
将项目切换到Project,然后在main下面新建一个proto文件夹。
在此文件夹下新建study.proto文件,然后AS会发现打开这个格式需要安装一个插件。
点击Install plugins进行安装。
安装成功之后,重启AS插件生效。
注意看这个文件的图标变了,这说明你的插件安装成功并且配置成功了。
3. 配置proto文件
里面的代码如下:
// 声明协议, 也支持 prota2,普遍使用proto3
syntax = “proto3”;
/**
- 通过potorbuf 描述对象生成java类。
*/
option java_package = “com.llw.datastore”;//设置生成的类所在的包
option java_multiple_files = true;//可能会有多个文件。
message PersonPreferences {
string name = 1;
int32 age = 2;
}
这里要按照Protobuf的语言规则去设置,参考protobuf 语言指南
这里我们定了一个对象,然后你可以Make Project,此时通过编译时技术,会生成一个PersonPreferences类,下面我们创建一个序列化器。
4. 创建序列化器
在com.llw.datastore下新建一个data包,包下新建一个PersonSerializer的单例,里面的代码如下:
object PersonSerializer : Serializer {
override val defaultValue: PersonPreferences = PersonPreferences.getDefaultInstance()
override suspend fun readFrom(input: InputStream): PersonPreferences {
try {
return PersonPreferences.parseFrom(input)
} catch (exception: InvalidProtocolBufferException) {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
尾声
如果你想成为一个优秀的 Android 开发人员,请集中精力,对基础和重要的事情做深度研究。
对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。
这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。
PS:之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
架构篇
《Jetpack全家桶打造全新Google标准架构模式》
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
mg src=“https://i-blog.csdnimg.cn/blog_migrate/a20747abca04decdce57ae32cd018584.jpeg” />
尾声
如果你想成为一个优秀的 Android 开发人员,请集中精力,对基础和重要的事情做深度研究。
对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。
这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。[外链图片转存中…(img-g8yDgJEa-1712338624351)]
PS:之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
[外链图片转存中…(img-GUyfwoyB-1712338624351)]
架构篇
《Jetpack全家桶打造全新Google标准架构模式》
[外链图片转存中…(img-3kDcPF0v-1712338624351)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!