IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 【Jectpack】DataStore -> 正文阅读

[移动开发]【Jectpack】DataStore

dataStore 是jectpack推出的轻量化存储组件,包含PreferenceDataStore和ProtoDataStore两种方式,基于Flow()实现数据存储

Why To Use

之前的Android轻量化存储组件SharedPreferences读写操作会阻塞主线程,在数据量不多的情况下没什么影响,但随着对组件的滥用,存储的数据量逐渐增大,性能问题逐渐显现,官方也挣扎着出了apply()异步化方案,希望挽救SharedPreferences于水火,但可惜apply()并未实现真正意义上的异步,只能另立新王DataStore,两者区别如下

功能SharePreferencesPreferenceDataStorePotoDataStore
是否阻塞主线程YNN
是否线程安全NYY
是否支持跨进程YNN
是否类型安全NNY
是否能监听数据变化NYY

How To Use

PreferenceDataStore

  1. 引入依赖
implementation 'androidx.datastore:datastore-preferences:1.0.0'
  1. 初始化对象
val preDataStore:DataStore<Preferences> by preferencesDataStore(name="user")

也可以使用Context拓展函数初始化(需引入implementation 'androidx.datastore:datastore-preferences:1.0.0-alpha05' 在1.0.0版本中没有该方法,不知为啥)

private val dataStore by lazy {
        context.createDataStore(
            name = USER
        )
    }

本质都是调用PreferenceDataStoreFactory.create()方法初始化

INSTANCE = PreferenceDataStoreFactory.create(
                    corruptionHandler = corruptionHandler,
                    migrations = produceMigrations(applicationContext),
                    scope = scope
                ) {
                    applicationContext.preferencesDataStoreFile(name)
                }
  1. 写入数据
//保持数据到下的key键下方
    suspend fun saveDataToDataStore(key:String,value:String){
        preDataStore.edit { it[stringPreferencesKey(key)]=value }
    }

由于edit方法是一个挂起函数,所以保存方法也要声明为挂起函数,在协程中调用
4. 读取数据

 //从key键取值
     fun getDataFromDataStore(key: String): Flow<String?> {
        return preDataStore.data.map { it[stringPreferencesKey(key)] }
    }

注意返回的是Flow类型,使用时可通过flow的collect方法获取,由于collect也是挂起函数,所以也需运行在协程中

GlobalScope.launch(Dispatchers.Main) {
                getDataFromDataStore("key1").collect { tvShow.setText(it) }
            }

使用Dispatchers线程调度设置到主线程更新UI数据,需引入依赖

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"

ProtoDataStore

protoDataStore 最大的特点就是类型安全,通过序列化对象存储数据

  1. 引入依赖
implementation 'androidx.datastore:datastore-core:1.0.0'
implementation 'com.google.protobuf:protobuf-java:3.14.0'
implementation 'com.google.protobuf:protoc:3.14.0'

根目录下

classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.13'

app gradle 里配置
plugins {
id ‘com.google.protobuf’
}
在android 同级配置闭包
protobuf {
protoc {
artifact = ‘com.google.protobuf:protoc:3.14.0’ // 也可以配置本地编译器路径
}

generateProtoTasks {
    all().each { task ->
        task.builtins {
            remove java
        }
        task.builtins {
            java {}// 生产java源码
        }
    }
}

}
android闭包下指定proto文件路径
sourceSets {
main {
java {
srcDir ‘src/main/java’
}
proto {
srcDir ‘src/main/proto’ //指定.proto文件路径
}
}
}

  1. 定义架构
    app/src/main/proto/目录的proto文件中定义架构,用于保存对象的类型,使用的是protobuf 语言
syntax = "proto3";

option java_package = "com.example.application";
option java_multiple_files = true;

message User {
  int32 age = 1;
  string userName=2;
}

主要是对message修饰的类进行定义,定义完后重构项目使proto文件生效

  1. 定义proto DataStore 对象
    3.1 实现Serializer类,T为proto文件定义的类型,重写读取和写入的方法
object UserSerializer:Serializer<User>{
        override val defaultValue: User
            get() = User.getDefaultInstance()

        override suspend fun readFrom(input: InputStream): User {
            try {
                return User.parseFrom(input)
            }catch (e: InvalidProtocolBufferException){
                throw CorruptionException("Cannot read proto.", e)
            }
        }
        override suspend fun writeTo(t: User, output: OutputStream) {
            t.writeTo(output)
        }
    }

3.2 通过UserSerializer得到Proto DataStore对象:

val userDataStore:DataStore<User> by dataStore(fileName = "user.pb",serializer = UserSerializer)

本质是调用DataStoreFactory.create()方法获取对象

   DataStoreFactory.create(
                   serializer = serializer,
                   produceFile = { applicationContext.dataStoreFile(fileName) },
                   corruptionHandler = corruptionHandler,
                   migrations = produceMigrations(applicationContext),
                   scope = scope
               )
  1. 设置值
suspend fun saveDataUseProto(age : Int,name:String){
        userDataStore.updateData { user->
            user.toBuilder().setAge(age)
                .setUserName(name)
                .build()
        }
    }

User对象中设置了age和name两个值,动态生成的User文件提供build方法设置属性值

  1. 获取值
fun getDataUseProto():Flow<User>{
        return userDataStore.data.map { it }
    }

这里it代指User对象,通过对flow操作可以获取user中的值

问题

之前使用SharedPreferences的项目如何更换到DataStore中?

在DataStore函数的创建方法中,有个参数produceMigrations,传人SharedPreferences的文件名进行初始化即可将文件内容设置到DataStore中

fun preferencesDataStore(
    name: String,
    corruptionHandler: ReplaceFileCorruptionHandler<Preferences>? = null,
    produceMigrations: (Context) -> List<DataMigration<Preferences>> = { listOf() },
    scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
): ReadOnlyProperty<Context, DataStore<Preferences>> {
    return PreferenceDataStoreSingletonDelegate(name, corruptionHandler, produceMigrations, scope)
}

由创建函数可知produceMigrations 是一个list类型的数组,说明可以一次将sp文件全部转换完毕,转换完后原来的sp文件将会删除

val preDataStore2:DataStore<Preferences> by preferencesDataStore(name="user",produceMigrations ={listOf<DataMigration<Preferences>>(SharedPreferencesMigration(this,"user"))})

DataStore如何在同步代码中使用

使用阻塞方法获取值val exampleData = runBlocking { context.dataStore.data.first() },但如果都只是使用阻塞方式调用就可能导致UI线程卡顿,所以DataStore 又提供了预读取功能来预先加载,这样即使是阻塞调用也不会损耗太多性能

override fun onCreate(savedInstanceState: Bundle?) {
    lifecycleScope.launch {
        context.dataStore.data.first()
        // You should also handle IOExceptions here.
    }
}

实践

GitHub DataStoreDemo

参考

在Android中使用proto
一文玩转dataStore
DataStore|Android 开发者

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-12-06 15:23:13  更:2021-12-06 15:23:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:47:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码