
我們之前已經(jīng) 分享 了 Proto DataStore 和 Preferences DataStore 的使用方法。這兩個 DataStore 版本都會在后臺使用 Protos 對數(shù)據(jù)進(jìn)行序列化。您也可以使用 Kotlin 序列化,結(jié)合使用 DataStore 與自定義數(shù)據(jù)類。這有助于減少樣板代碼,且無需學(xué)習(xí)或依賴于 Protobuf 庫,同時仍可以為數(shù)據(jù)提供架構(gòu)。
您需要完成以下幾項操作:
- 定義數(shù)據(jù)類
- 確保您的數(shù)據(jù)類不可變
- 使用 Kotlin 序列化實現(xiàn) DataStore 序列化器
- 開始使用
定義數(shù)據(jù)類
Kotlin 數(shù)據(jù)類 非常適合與 DataStore 結(jié)合使用,這是因為它們能夠與 Kotlin 序列化無縫協(xié)作。DataStore 會依賴數(shù)據(jù)類自動生成的 equals 和 hashCode。數(shù)據(jù)類也會生成便于調(diào)試和更新數(shù)據(jù)的 toString 和 copy 函數(shù)。
/* Copyright 2021 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
data class UserPreferences(
val showCompleted: Boolean,
val sortOrder: SortOrder
)
確保您的數(shù)據(jù)類不可變
確保您的數(shù)據(jù)類不可變是非常重要的,這是因為 DataStore 無法兼容可變類型。結(jié)合使用可變類型與 DataStore 會導(dǎo)致難以捕獲的錯誤和競爭條件。數(shù)據(jù)類并非一定不可變。
Vars 是可變的,所以您應(yīng)使用 vals 代替:
/* Copyright 2021 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
data class MyData(
- var num: Int
+ val num: Int
)
- myObj.num = 5 // Fails to compile when num is val
+ val newObj = myObj.copy(num = 5)
數(shù)組是可變的,所以您不應(yīng)將其公開。
/* Copyright 2021 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
data class MyData(
- var num: IntArray
)
- myObj.num = 5 // This would mutate your object
即使將只讀列表用作數(shù)據(jù)類的一部分,該數(shù)據(jù)類也仍為可變的。您應(yīng)考慮改用 不可變/持久化集合:
/* Copyright 2021 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
data class MyData(
- val nums: List<Int>
+ val nums: PersistentList<Int>
)
- val myInts = mutableListOf(1, 2, 3, 4)
- val myObj = MyData(myInts)
- myInts.add(5) // Fails to compile with PersistentList, but mutates with List
+ val newData = myObj.copy(
+ nums = myObj.nums.mutate { it += 5 } // Mutate returns a new PersistentList
+ )
將可變類型用作數(shù)據(jù)類的一部分會令數(shù)據(jù)類變?yōu)榭勺儬顟B(tài)。您不應(yīng)采取上述做法,反而要確保所有內(nèi)容都是不可變類型。
/* Copyright 2021 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
data class MyData(
- val mutableType: MutableType
)
- val myType = MutableType()
- val myObj = MyData(myType)
- myType.mutate()
實現(xiàn) DataStore 序列化器
Kotlin 序列化支持包括 JSON 和協(xié)議緩沖區(qū)在內(nèi)的 多種格式。我將在此處使用 JSON,因為它十分常見、易于使用且會以明文形式進(jìn)行存儲,便于調(diào)試。Protobuf 也是一個不錯的選擇,因為它規(guī)模更小、速度更快且兼容 protobuf-lite。
要使用 Kotlin 序列化讀取數(shù)據(jù)類并將其寫入 JSON,您需要使用 @Serializable 注釋數(shù)據(jù)類并使用 Json.decodeFromString<YourType>(string) 和 Json.encodeToString(data)。以下是帶有 UserPreferences 的示例:
/* Copyright 2021 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
@Serializable
data class UserPreferences(
val showCompleted: Boolean = false,
val sortOrder: SortOrder = SortOrder.None
)
object UserPreferencesSerializer : Serializer<UserPreferences> {
override val defaultValue = UserPreferences()
override suspend fun readFrom(input: InputStream): UserPreferences {
try {
return Json.decodeFromString(
UserPreferences.serializer(), input.readBytes().decodeToString())
} catch (serialization: SerializationException) {
throw CorruptionException("Unable to read UserPrefs", serialization)
}
}
override suspend fun writeTo(t: UserPreferences, output: OutputStream) {
output.write(Json.encodeToString(UserPreferences.serializer(), t).encodeToByteArray())
}
}
?? 將 Parcelables 與 DataStore 一起使用并不安全,因為不同 Android 版本之間的數(shù)據(jù)格式可能會有所變化。
使用序列化器
在您構(gòu)建時,將您創(chuàng)建的序列化器傳遞到 DataStore:
/* Copyright 2021 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
val Context.dataStore by dataStore("my_file.json", serializer = UserPreferencesSerializer)
其讀取數(shù)據(jù)看起來與使用 protos 進(jìn)行讀取一樣:
/* Copyright 2021 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
suspend fun getShowCompleted(): Boolean {
context.dataStore.data.first().showCompleted
}
您可以使用生成的 .copy() 函數(shù)更新數(shù)據(jù):
/* Copyright 2021 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
suspend fun setShowCompleted(newShowCompleted: Boolean) {
// This will leave the sortOrder value untouched:
context.dataStore.updateData { it.copy(newShowCompleted = showCompleted) }
}
總結(jié)
結(jié)合使用 DataStore 與 Kotlin 序列化和數(shù)據(jù)類可減少樣板文件并有助于簡化代碼,但您必須多加小心,避免因為可變性而引發(fā)錯誤。您只需定義數(shù)據(jù)類和實現(xiàn)序列化器即可??靵韯邮謬L試一下吧!
如要詳細(xì)了解 DataStore,您可以查看我們的 文檔 并獲得一些使用 Proto DataStore 和 Preferences DataStore Codelab 的實踐經(jīng)驗。