赞
踩
// ContextImpl.getSharedPreferences() public SharedPreferences getSharedPreferences(File file, int mode) { SharedPreferencesImpl sp; synchronized (ContextImpl.class) { final ArrayMap<File, SharedPreferencesImpl> cache = getSharedPreferencesCacheLocked(); sp = cache.get(file); if (sp == null) { ... sp = new SharedPreferencesImpl(file, mode); cache.put(file, sp); return sp; } } //MODE_MULTI_PROCESS只是重新加载一下sp,并不能保证跨进程安全的 if ((mode & Context.MODE_MULTI_PROCESS) != 0 || getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB) { // If somebody else (some other process) changed the prefs // file behind our back, we reload it. This has been the // historical (if undocumented) behavior. sp.startReloadIfChangedUnexpectedly(); } return sp; } //1. SharedPreferences对象的创建会开启异步线程读取数据 //SharedPreferencesImpl.startLoadFromDisk() private void startLoadFromDisk() { synchronized (mLock) { mLoaded = false; } new Thread("SharedPreferencesImpl-load") { public void run() { loadFromDisk(); } }.start(); } //2. SharedPreferences.getXX()是同步的,会调用wait方法等待对象加载完毕,就可能导致ANR public String getString(String key, @Nullable String defValue) { synchronized (mLock) { awaitLoadedLocked(); String v = (String)mMap.get(key); return v != null ? v : defValue; } } //3. SharedPreferences.apply()是异步的,但是当生命周期处于handleStopService(),handlePauseActivity(), //handleStopActivity() 时, 会一直等待apply()方法将数据保存成功,否则会一直等待,就可能导致ANR;
// 使用静态的ArrayMap缓存每个SP文件,在ContextImpl.getSharedPreferences()中调用 private static ArrayMap<String, ArrayMap<File, SharedPreferencesImpl>> sSharedPrefsCache; private ArrayMap<File, SharedPreferencesImpl> getSharedPreferencesCacheLocked() { if (sSharedPrefsCache == null) { sSharedPrefsCache = new ArrayMap<>(); } final String packageName = getPackageName(); ArrayMap<File, SharedPreferencesImpl> packagePrefs = sSharedPrefsCache.get(packageName); if (packagePrefs == null) { packagePrefs = new ArrayMap<>(); sSharedPrefsCache.put(packageName, packagePrefs); } return packagePrefs; }
val sp=getSharedPreferences("ljy.sp",Context.MODE_PRIVATE)
//sp.edit默认是apply,可以手动设置为commit
//apply:提交会先写入内存,然后异步写入磁盘
//commit:直接写入磁盘
//如果频繁操作的话 apply 的性能会优于 commit
//提交数据时, 尽量使用apply,而非commit,仅当需要确定提交结果,并据此有后续操作时,使用commit;
sp.edit(commit = true) {
putString("name", "洋仔")
putInt("age", 17)
}
val name=sp.getBoolean("name",false)
val age=sp.getInt("age",false)
//(1) Datastore Preferences
implementation "androidx.datastore:datastore-preferences:1.0.0-alpha08"
// optional - RxJava2 support
implementation("androidx.datastore:datastore-preferences-rxjava2:1.0.0-rc02")
object Constants { //SharedPreferences文件名 const val MY_SP = "mySP" //DataStore<Preferences>文件名 const val MY_PREFERENCES = "myPreferences" //SharedPreferences 迁移到 DataStore<Preferences> 后的文件名 const val SP_2_PREFERENCES = "sp2Preferences" //SharedPreferences中的key const val KEY_NAME_SP = "name" //SharedPreferences 迁移到 DataStore<Preferences> 后的key val KEY_NAME = stringPreferencesKey(KEY_NAME_SP) //DataStore<Preferences> 中的key val KEY_USER_NAME = stringPreferencesKey("userName") val KEY_USER_AGE = intPreferencesKey("userAge") }
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = Constants.MY_PREFERENCES)
//1. 存储键值对数据 dataStore.edit { it[Constants.KEY_USER_NAME] = "jinYang" it[Constants.KEY_USER_AGE] = 18 } //2. 读取键值对数据 dataStore.data.collect { LjyLogUtil.d("userName:${it[Constants.KEY_USER_NAME]}") LjyLogUtil.d("userAge:${it[Constants.KEY_USER_AGE]}") LjyLogUtil.d("$Constants.KEY_NAME:${it[Constants.KEY_NAME]}") LjyLogUtil.d("it:$it") } //或者使用LiveData dataStore.data.asLiveData().observe(this,){ LjyLogUtil.d("asLiveData:userName:${it[Constants.KEY_USER_NAME]}") LjyLogUtil.d("asLiveData:userAge:${it[Constants.KEY_USER_AGE]}") LjyLogUtil.d("asLiveData:it:$it") } //3. 清除数据 dataStore.edit { it.clear() }
//1. 构建DataStore时,produceMigrations参数传入一个SharedPreferencesMigration的集合, // 即可把多个sp文件关联到DataStore val Context.dataStore2 by preferencesDataStore( name = Constants.SP_2_PREFERENCES, produceMigrations = { context -> // Since we're migrating from SharedPreferences, add a migration based on the // SharedPreferences name listOf(SharedPreferencesMigration(context, Constants.MY_SP)) } ) //2. 需要执行一次读/写操作才能完成迁移,迁移成功后会自动删除sp文件, // 需要注意的是迁移工作只执行一次,迁移成功后需要停止再使用sp dataStore2.data.collect { LjyLogUtil.d("it:$it") }
//1. 添加协议缓冲区插件 plugins { ... id "com.google.protobuf" version "0.8.12" } //2 添加协议缓冲区和 Proto DataStore 依赖项 implementation("androidx.datastore:datastore:1.0.0-rc02") //protobuf implementation "com.google.protobuf:protobuf-javalite:3.10.0" // optional - RxJava2 support implementation("androidx.datastore:datastore-rxjava2:1.0.0-rc02") //3. 配置协议缓冲区 protobuf { // 设置 protoc 的版本 protoc { // //从仓库下载 protoc 这里的版本号需要与依赖 com.google.protobuf:protobuf-javalite:xxx 版本相同 artifact = 'com.google.protobuf:protoc:3.10.0' } generateProtoTasks { all().each { task -> task.builtins { java { option "lite" } } } } // 默认生成目录 $buildDir/generated/source/proto 通过 generatedFilesBaseDir 改变生成位置 generatedFilesBaseDir = "$projectDir/src/main" } //4. 设置 proto 文件位置 android { sourceSets { main { proto { // proto 文件默认路径是 src/main/proto // 可以通过 srcDir 修改 proto 文件的位置 srcDir 'src/main/proto' } } } }
syntax = "proto3"; //版本
//包名
option java_package = "com.jinyang.jetpackdemo.datastore";
option java_multiple_files = true;
option java_outer_classname = "UserInfoProto";
message User {
//格式:字段类型 + 字段名称 + 字段编号
string name = 1
int32 age = 2
bool isMarried = 3;
}
object UserSerializer:Serializer<User>{
override val defaultValue: User
get() = User.getDefaultInstance()
override suspend fun readFrom(input: InputStream): User {
return User.parseFrom(input)
}
override suspend fun writeTo(t: User, output: OutputStream) {
t.writeTo(output)
}
}
val Context.userInfoStore: DataStore<User> by dataStore(
fileName = "userInfo.pb",
serializer = UserSerializer
)
private fun dataStoreProto() { // 注册观察者读取内容 userInfoStore.data.asLiveData().observe(this) { LjyLogUtil.d("asLiveData:it:$it") LjyLogUtil.d("name:${it.name}") LjyLogUtil.d("age:${it.age}") LjyLogUtil.d("isMarried:${it.isMarried}") } lifecycleScope.launch { //将内容写入 Proto DataStore userInfoStore.updateData { it.toBuilder() .setName("今阳") .setAge(18) .setIsMarried(true) .build() } //使用collect读取内容 userInfoStore.data.collect { LjyLogUtil.d("collect: it:$it") } } // DataStore 的主要优势之一是异步 API,但可能不一定始终能将周围的代码更改为异步代码。 // 如果您使用的现有代码库采用同步磁盘 I/O,或者您的依赖项不提供异步 API,就可能出现这种情况。 // Kotlin 协程提供 runBlocking() 协程构建器,以帮助消除同步与异步代码之间的差异。 // 您可以使用 runBlocking() 从 DataStore 同步读取数据。RxJava 在 Flowable 上提供阻塞方法。 // 以下代码会阻塞发起调用的线程,直到 DataStore 返回数据: val user = runBlocking { userInfoStore.data.first() } LjyLogUtil.d("runBlocking: user:$user") //对界面线程执行同步 I/O 操作可能会导致 ANR 或界面卡顿。您可以通过从 DataStore 异步预加载数据来减少这些问题: lifecycleScope.launch { val user = userInfoStore.data.first() LjyLogUtil.d("user:$user") } }
//1. 创建DataStore,并将sp的键值对映射到User val Context.userInfoStore2: DataStore<User> by dataStore( fileName = "userInfo2.pb", serializer = UserSerializer, produceMigrations = { context -> listOf(SharedPreferencesMigration(context, Constants.MY_SP) { sharedPrefs, user -> //将sp的键值对映射到User user.toBuilder() .setName(sharedPrefs.getString(Constants.KEY_NAME_SP)) .setAge(sharedPrefs.getInt(Constants.KEY_NAME_SP,0)) .setIsMarried(false) .build() }) } ) //2. 执行一次读写 lifecycleScope.launch { val user = userInfoStore2.data.first() LjyLogUtil.d("user:$user") }
implementation 'com.tencent:mmkv-static:1.2.10'
val rootDir = MMKV.initialize(this)
LjyLogUtil.d(rootDir)
//默认为:/data/user/0/com.jinyang.jetpackdemo/files/mmkv
//获取单例 val kv = MMKV.defaultMMKV() //写入数据 kv.encode("name", "LJY") kv.encode("age", 16) kv.encode("isMarried", true) //读取数据 val name = kv.decodeString("name") LjyLogUtil.d("name=$name") val age = kv.decodeInt("age") LjyLogUtil.d("age=$age") val isMarried = kv.decodeBool("isMarried") LjyLogUtil.d("isMarried=$isMarried") //删除数据 kv.removeValueForKey("age"); LjyLogUtil.d("age=${kv.decodeInt("age")}")
val kvUser = MMKV.mmkvWithID("userInfo")
kvUser.encode("name", "yang")
LjyLogUtil.d("name=${kvUser.decodeString("name")}")
val kvSetting = MMKV.mmkvWithID("settings", MMKV.MULTI_PROCESS_MODE)
kvSetting.encode("key", "abc")
LjyLogUtil.d("key=${kvSetting.decodeString("key")}")
// val preferences = getSharedPreferences("myData", MODE_PRIVATE) val sp2mmkv: MMKV = MMKV.mmkvWithID("myData") // 迁移旧数据: val sp = getSharedPreferences(Constants.MY_SP, MODE_PRIVATE) sp2mmkv.importFromSharedPreferences(sp) sp.edit().clear().apply() // 跟以前用法一样 sp2mmkv.edit(commit = true){ putBoolean("bool", true) val set = HashSet<String>() set.add("a") set.add("b") set.add("c") putStringSet("string-set", set) } LjyLogUtil.d("name=${sp2mmkv.getString(Constants.KEY_NAME_SP,"")}") LjyLogUtil.d("age=${sp2mmkv.getInt(Constants.KEY_AGE_SP,0)}") LjyLogUtil.d("bool=${sp2mmkv.getBoolean("bool",false)}") LjyLogUtil.d("string-set=${sp2mmkv.getStringSet("string-set", emptySet())}")
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。