如果你已經知道什麼是 Sharedpeference 那就不能不了解一下什麼是 DataStore,以下如有解釋不清或是描述錯誤的地方還請大家多多指教:
為一種輕量級的資料儲存方式,如果有較複雜的資料型態請使用 Room 來取代:
Note:
If you need to support large or complex datasets, partial updates, or referential integrity, consider using Room instead.
referential integrity
(參照完整性) refers to the relationship between tables
是 Google 目標用來取代 SharedPreference 的輕量型儲存方式,運用 Kotlin coroutine 及 flow 進行非同步儲存,克服一些 SharedPreference 的缺點,目前主要分成兩種儲存類別:
這次會將 DataStore 用在設定頁上,目前設定頁有一個紫外線提醒的開關,利用 DataStore 來儲存開關的是否開啟:
先加入 dependency (Preferences 和 Proto 分別為不一樣的 dependency )
dependencies {
...
implementation "androidx.datastore:datastore-preferences:1.0.0"
implementation "androidx.datastore:datastore-core:1.0.0"
...
}
// AppStored.kt
class AppStored(private val dataStore: DataStore<Preferences>) {
}
建立 key object,以往的 SharedPreferences 是以單純的文字當作 key,DataStore 必須建立一個 object :
class AppStored(private val dataStore: DataStore<Preferences>) {
// DataStore
private val UVA_WARN= booleanPreferencesKey("uva_warn")
// SharedPreference
private val UVA_WARN= "uva_warn"
}
寫入的 function 跟 SharedPreferences 依樣是呼叫 edit() ,但不同的是 DataStore 所提供的是 suspending function :
...
suspend fun enableUVAWarn(enable: Boolean) {
dataStore.edit { preferences ->
// write value
preferences[UVA_WARN] = enable
}
}
...
當讀取時勢必會有 error 的產生,這時可在讀取時加入 catch,如果是 IOException 可回傳 emptyPreferences()
,其他類型的就建議直接拋出這個 exception:
val uvaPreferencesFlow: Flow<Boolean> = dataStore.data
.catch { exception ->
// dataStore.data throws an IOException when an error is encountered when reading data
if (exception is IOException) {
Log.e("error", "Error reading preferences.", exception)
emit(emptyPreferences())
} else {
throw exception
}
}.map { preferences ->
preferences[UVA_WARN]?: false
}
與 SharedPreference 相同,使用 clear() 和 remove(keyName),目前依功能不需要使用:
suspend fun clearPreferences () {
context.dataStore.edit { preferences ->
preferences.clear()
// remove single
preferences.remove(UVA_WARN)
}
}
在設定頁操作:
// At the top level of your kotlin file:
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
...
private val appStored by lazy { AppStored(requireContext().dataStore) }
...
private fun setupView() = binding.apply {
...
uvaSetting.apply {
lifecycleScope.launch {
appStored.uvaPreferencesFlow.collect {
isChecked = it
}
setOnCheckedChangeListener { _, isChecked ->
appStored.enableUVAWarn(isChecked)
}
}
}
}