DataStore(三)Proto DataStore
DataStore不仅可以替代SharedPreferences,储存键值对,避免ANR问题,它还能够储存使用Protocol Buffers序列化过后的对象。
Protocol Buffers是Google提供的一种结构化数据储存格式。在DataStore中使用该格式对对象进行序列化和保存。
下面,我们一起来看看如何在DataStore中使用它。
1.第一步,需要在build.gradle文件中添加插件。
plugins {
id "com.google.protobuf" version "0.8.12"//使用proto需要的插件
android {
protobuf { //使用proto需要的插件
protoc {
artifact = "com.google.protobuf:protoc:3.10.0"
generateProtoTasks {
all().each { task ->
task.builtins {
java {
option 'lite'
dependencies {
implementation "androidx.datastore:datastore-preferences:1.0.0-alpha08"
implementation "androidx.datastore:datastore:1.0.0-alpha08"
implementation "com.google.protobuf:protobuf-javalite:3.10.0" //使用proto需要的插件
}
2.在 src/main/proto 目录下定义好.proto文件,通过Android Studio的Build功能,对整个项目进行编译,即可自动为你生成相关的代码。
假设我们定义了一个名为user_prefs.proto的文件。
syntax = "proto3";
option java_package = "com.michael.datastore";
option java_multiple_files = true;
message UserPreferences {
string name = 1;
int32 age = 2;
bool sex = 3;
}
注意,字段中的1,2,3并不是字段的值,而是编号。关于Protocol Buffers的相关内容,大家可以自行搜索学习。不是本文所讨论的重点。
在编译完成后,可以看到Android Studio为我们生成的代码。
3.接下来,我们需要手动写一个Serializer类,用于序列化刚才Android Studio为我们生成的类文件UserPreferences。
object UserPreferencesSerializer : Serializer<UserPreferences> {
override val defaultValue: UserPreferences = UserPreferences.getDefaultInstance()
override 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)
}
4.这些准备工作都做完以后,接下来就是DataStore的创建。依然,是通过属性委托进行创建。其中需要将我们刚才所写的Serializer类以参数的形式传入。
const val DATA_STORE_FILE_NAME = "user_prefs.pb"
//通过属性委托的方式创建
val Context.userProtoDataStore: DataStore<UserPreferences> by dataStore(
fileName = DATA_STORE_FILE_NAME,
serializer = UserPreferencesSerializer
object ProtoDataStore {
private const val TAG: String = "ProtoDataStore"
suspend fun read(context: Context) :Flow<UserPreferences>{
return context.userProtoDataStore.data
.catch { exception ->
if (exception is IOException) {
Log.e(TAG, "Error reading sort order preferences.", exception)
emit(UserPreferences.getDefaultInstance())
} else {
throw exception
suspend fun write(context: Context, name: String, age: Int, sex: Boolean) {
context.userProtoDataStore.updateData { currentPreferences ->
currentPreferences.toBuilder().setName(name).setAge(age).setSex(sex).build()
}
5.读取和写入Proto DataStore
findViewById<Button>(R.id.btnPutProto).setOnClickListener {
GlobalScope.launch {
ProtoDataStore.write(applicationContext, "michael", 33, true)
Log.e(">>>>>>>>>>>>", "写入数据")
findViewById<Button>(R.id.btnGetProto).setOnClickListener {
GlobalScope.launch {
Log.e(">>>>>>>>>>>>", "读取数据")
try {
val userPreferencesFlow: Flow<UserPreferences> =
ProtoDataStore.read(applicationContext)
userPreferencesFlow.collect { preferences ->
Log.e(">>>>>>>>>>", "name:" + preferences.name)
Log.e(">>>>>>>>>>", "age" + preferences.age)
Log.e(">>>>>>>>>>", "sex" + preferences.sex)