在开发过程中经常会遇到需要在本地存储轻量数据,以往都是通过SharedPreferences来实现,但现在官方推荐使用DataStore来替代。
本篇文章介绍下如何使用Preferences DataStore来替代SharedPreferences。
DataStore简介
DataStore是一种数据存储解决方案,使用Kotlin协程和Flow以异步、一致的事务方式来存储数据。分为:
- Preferences DataStore:类似SharedPreferences,采用键值对的方式来存储数据。
- Proto DataStore:将数据作为自定义数据类型的实例进行存储。
Preferences DataStore
1.在项目中引入Preferences DataStore
在项目app module的build.gradle中的defaultConfig中添加依赖:
implementation("androidx.datastore:datastore-preferences:1.0.0")
//如果使用Rxjava
//Rxjava2的支持
implementation("androidx.datastore:datastore-preferences-rxjava2:1.0.0")
//Rxjava3的支持
implementation("androidx.datastore:datastore-preferences-rxjava3:1.0.0")
如果有开启混淆,则还需要在混淆文件中添加:
-keepclassmembers class * extends androidx.datastore.preferences.protobuf.GeneratedMessageLite {
<fields>;
}
2.Preferences DataStore的使用
- 创建Preferences DataStore 使用由preferencesDataStore创建的属性委托来创建实例。创建后,就可以在应用内通过context.dataStore来访问该实例。
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "StoreName")
- 存取数据 存取数据之前,需要使用键类型函数为值定义一个键。键类型函数包括:
- intPreferencesKey(name: String)
- doublePreferencesKey(name: String)
- stringPreferencesKey(name: String)
- booleanPreferencesKey(name: String)
- floatPreferencesKey(name: String)
- longPreferencesKey(name: String)
- stringSetPreferencesKey(name: String)
接下来使用intPreferencesKey介绍一下如何存取数据。
class TestActivity: Activity() {
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "StoreName")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.layout_test_activity)
//存数据
lifecycleScope.launch{
saveIntValue(this@TestActivity, "TestInt", 100)
}
//取数据
val btnGetValue = findViewById<Button>(R.id.get_value)
btnGetValue.setOnClickListener {
lifecycleScope.launch{
val intValue = getIntValue(this@TestActivity, "TestInt",0)
Log.e("test", "get int value:$intValue")
}
}
}
suspend fun saveIntValue(context: Context, keyName: String, value: Int) {
val key = intPreferencesKey(keyName)
context.dataStore.edit {
it[key] = value
}
}
suspend fun getIntValue(context: Context, keyName: String, defaultValue: Int? = null): Int {
val key = intPreferencesKey(keyName)
return context.dataStore.data.map {
it[key] ?: (defaultValue ?: 0)
}.first()
}
}
Preferences DataStore的工具类
针对Preferences DataStore进行了简单的封装便于使用,代码如下:
import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.*
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
class DataStorePreferencesHelper private constructor(var storeName: String? = null) {
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = storeName
?: "MiniGamePreferencesDataStore")
companion object {
@Volatile
private var dataStorePreferencesHelper: DataStorePreferencesHelper? = null
fun getInstance(storeName: String? = null): DataStorePreferencesHelper {
if (dataStorePreferencesHelper == null) {
synchronized(DataStorePreferencesHelper::class.java) {
if (dataStorePreferencesHelper == null) {
dataStorePreferencesHelper = DataStorePreferencesHelper(storeName)
}
}
}
return dataStorePreferencesHelper!!
}
}
suspend fun saveIntValue(context: Context, keyName: String, value: Int) {
val key = intPreferencesKey(keyName)
context.dataStore.edit {
it[key] = value
}
}
suspend fun getIntValue(context: Context, keyName: String, defaultValue: Int? = null): Int {
val key = intPreferencesKey(keyName)
return context.dataStore.data.map {
it[key] ?: (defaultValue ?: 0)
}.first()
}
suspend fun saveLongValue(context: Context, keyName: String, value: Long) {
val key = longPreferencesKey(keyName)
context.dataStore.edit {
it[key] = value
}
}
suspend fun getLongValue(context: Context, keyName: String, defaultValue: Long? = null): Long {
val key = longPreferencesKey(keyName)
return context.dataStore.data.map {
it[key] ?: (defaultValue ?: 0L)
}.first()
}
suspend fun saveFloatValue(context: Context, keyName: String, value: Float) {
val key = floatPreferencesKey(keyName)
context.dataStore.edit {
it[key] = value
}
}
suspend fun getFloatValue(context: Context, keyName: String, defaultValue: Float? = null): Float {
val key = floatPreferencesKey(keyName)
return context.dataStore.data.map {
it[key] ?: (defaultValue ?: 0f)
}.first()
}
suspend fun saveDoubleValue(context: Context, keyName: String, value: Double) {
val key = doublePreferencesKey(keyName)
context.dataStore.edit {
it[key] = value
}
}
suspend fun getDoubleValue(context: Context, keyName: String, defaultValue: Double? = null): Double {
val key = doublePreferencesKey(keyName)
return context.dataStore.data.map {
it[key] ?: (defaultValue ?: 0.0)
}.first()
}
suspend fun saveBooleanValue(context: Context, keyName: String, value: Boolean) {
val key = booleanPreferencesKey(keyName)
context.dataStore.edit {
it[key] = value
}
}
suspend fun getBooleanValue(context: Context, keyName: String, defaultValue: Boolean? = null): Boolean {
val key = booleanPreferencesKey(keyName)
return context.dataStore.data.map {
it[key] ?: (defaultValue ?: false)
}.first()
}
suspend fun saveStringValue(context: Context, keyName: String, value: String) {
val key = stringPreferencesKey(keyName)
context.dataStore.edit {
it[key] = value
}
}
suspend fun getStringValue(context: Context, keyName: String, defaultValue: String? = null): String {
val key = stringPreferencesKey(keyName)
return context.dataStore.data.map {
it[key] ?: (defaultValue ?: "")
}.first()
}
suspend fun saveStringSetValue(context: Context, keyName: String, value: Set<String>) {
val key = stringSetPreferencesKey(keyName)
context.dataStore.edit {
it[key] = value
}
}
suspend fun getStringSetValue(context: Context, keyName: String, defaultValue: Set<String>? = null): Set<String> {
val key = stringSetPreferencesKey(keyName)
return context.dataStore.data.map {
it[key] ?: (defaultValue ?: setOf())
}.first()
}
}