DataStore出現(xiàn)的原因
Jetpack DataStore is a data storage solution that allows you to store key-value pairs or typed objects with protocol buffers. DataStore uses Kotlin coroutines and Flow to store data asynchronously, consistently, and transactionally.
If you're currently usingSharedPreferences
to store data, consider migrating to DataStore instead.
?官方文檔給出的定義如上所示
- 首先它的作用就是以
key-value
的形式去存儲(chǔ)數(shù)據(jù) - 它用的是
kotlin
的Flow實(shí)現(xiàn),以事務(wù)方式處理數(shù)據(jù)。 - 最關(guān)鍵的一句話就是如果你的項(xiàng)目當(dāng)前使用的是Sp,那么建議做一次遷移伐谈。
DataStore的實(shí)現(xiàn)方式
DataStore provides two different implementations: Preferences DataStore and Proto DataStore.
- Preferences DataStore stores and accesses data using keys. This implementation does not require a predefined schema, and it does not provide type safety.
- Proto DataStore stores data as instances of a custom data type. This implementation requires you to define a schema using protocol buffers, but it provides type safety.
?文檔中給出DataStore的兩種實(shí)現(xiàn)方式:
- Preferences DataStore 顧名思義忠聚,以鍵值對(duì)的方式存儲(chǔ)在本地。
-
Proto DataStore 通過(guò)
protocol buffers
將對(duì)象序列化存儲(chǔ)在本地柳弄。
DataStore的使用
- 在項(xiàng)目當(dāng)中集成舶胀,添加所需依賴
// Preferences DataStore
implementation "androidx.datastore:datastore-preferences:1.0.0-alpha03"
// Proto DataStore
implementation "androidx.datastore:datastore-core:1.0.0-alpha03"
- 創(chuàng)建一個(gè)DataStore對(duì)象
private val DATASTORE_NAME = "hy_datastore"
var dateStore: DataStore<Preferences> = mContext.createDataStore(name = DATASTORE_NAME)
- 將對(duì)象存入DataStore中
通過(guò)mDataStorePre.edit()
將數(shù)據(jù)存入DataStore中
public suspend fun DataStore<Preferences>.edit(
transform: suspend (MutablePreferences) -> Unit
): Preferences {
return this.updateData {
// It's safe to return MutablePreferences since we freeze it in
// PreferencesDataStore.updateData()
it.toMutablePreferences().apply { transform(this) }
}
}
可以看到edit()
方法是一個(gè)suspend
函數(shù)概说,所以只能在協(xié)程體中進(jìn)行調(diào)用。以掛起的方式進(jìn)行運(yùn)行嚣伐,做到不阻礙主線程糖赔。
private suspend fun saveDate(data: String) {
mDataStorePre.edit { mutablePreferences ->
mutablePreferences[KEY_TEST_DATASTORE] = ""
}
}
- 從DataStore中讀取對(duì)象
private suspend fun getDate(data: String): String {
var value = mDataStorePre.data.map { preferences ->
preferences[KEY_TEST_DATASTORE] ?: ""
}
return value.first()
}
可以看到DataStore的key
不同于sp
的key
,DataStore的key
是Preferences.Key<T>
類型轩端,只支持Int放典,Long,Boolean基茵,F(xiàn)loat奋构,String,Double
:
public inline fun <reified T : Any> preferencesKey(name: String): Preferences.Key<T> {
return when (T::class) {
Int::class -> {
Preferences.Key<T>(name)
}
String::class -> {
Preferences.Key<T>(name)
}
Boolean::class -> {
Preferences.Key<T>(name)
}
Float::class -> {
Preferences.Key<T>(name)
}
Long::class -> {
Preferences.Key<T>(name)
}
Double::class -> {
Preferences.Key<T>(name)
}
Set::class -> {
throw IllegalArgumentException("Use `preferencesSetKey` to create keys for Sets.")
}
else -> {
throw IllegalArgumentException("Type not supported: ${T::class.java}")
}
}
}
除此外的類型將會(huì)拋出異常。
- 通過(guò)mDataStorePre.data我們將獲取到的是一個(gè)
Flow<T>
的對(duì)象拱层,每當(dāng)數(shù)據(jù)變化的時(shí)候都會(huì)重新發(fā)出弥臼。 - 異常的捕獲我們通過(guò)catch來(lái)捕獲,如下所示:
private suspend fun getDate(): String {
var value = mDataStorePre.data.catch {
if (it is IOException) {//io異常的話可以發(fā)送一個(gè)emptyPreferences()來(lái)重新使用
it.printStackTrace()
emit(emptyPreferences())
} else {
throw it
}
}
.map { preferences ->
preferences[KEY_TEST_DATASTORE] ?: ""
}
return value.first()
}
遷移Sp到DataStore
只需要在創(chuàng)建的時(shí)候傳入需要遷移的SharedPreferencesMigration
如下:
var mDataStorePre: DataStore<Preferences> = mContext.createDataStore(
name = DATASTORE_NAME,
migrations = listOf(
SharedPreferencesMigration(
mContext,
SPUtil.NAME
)
)
)
- 遷移之后會(huì)自動(dòng)刪除Sp所使用的文件根灯,需要注意的是只從sp遷移一次径缅。