为什么我可以将枚举保存到 Firestore,但当我尝试检索它时应用程序会崩溃?
Why can I save an enum to Firestore, but it crashes the app when I try to retrieve the same?
我定义了以下内容:
enum class Venues (val nickname: String) {
Venue1 ("Venue 1"),
Venue2 ("Venue 2")
}
data class Tournament (var aString: String = "Title",
var aDate: Date = Date(),
var anInt: Int = 8,
var venue: Venues = Venues.Venue1,
var aBoolean: Boolean = true)
将 Tournament
写入 Firestore 的以下代码按预期工作:
fun createNewTournament(view: View) {
val teamCount = (8..24).random()
val venue: Venues = Venues.values().random()
val newTournament = Tournament("String", Date(), teamCount, venue, false)
tournamentsRef.add(newTournament)
.addOnSuccessListener { docRef -> Log.d ("ADD", "DocSnapShot has id: ${docRef.id}") }
.addOnFailureListener { e -> Log.w ("ADD", "Error adding document", e)}
}
查看 Firebase 控制台,我看到一个完整的 Tournament
文档,其中 venue
字段定义为 String
。
但是,当我尝试读取相同内容时,我的应用程序在 toObjects
行崩溃:
val tournamentsRef = FirebaseFirestore.getInstance().collection("tournaments")
var tournaments = ArrayList<Tournament>()
tournamentsRef.addSnapshotListener { snapshot, error ->
if (error != null) {
return@addSnapshotListener
}
// CRASH: this line crashes if enum is included
tournaments = snapshot!!.toObjects(Tournament::class.java) as ArrayList<Tournament>
}
如果我从 data class
中删除 venue
枚举,所有文档都被成功读取,但显然没有 venue
字段。
那么,如何将 enum
s 与 Firestore 一起使用,具体来说,我如何将传入的 String
转换为我的 enum
?
为了便于比较,这是我在此应用程序的 iOS 版本中使用的 Swift 代码:
enum Venues: String, CaseIterable, Codable {
case venue1 = "Venue 1"
case venue2 = "Venue 2"
}
struct Tournament: Codable {
var aString: String
var aDate: Date
var anInt: Int
var venue: Venues
var aBoolean: Bool
}
let tournamentsRef = Firestore.firestore().collection("tournaments")
var tournaments = [Tournament]()
tournamentsRef
.addSnapshotListener { querySnapshot, error in
guard let documents = querySnapshot?.documents else { return }
self.tournaments = documents.compactMap { document in
let tournament = try? document.data(as: Tournament.self)
return tournament
}
}
func createNewTournament() {
let newTournament = Tournament(aString: "String", aDate: Date(), anInt: 8, venue: Venues.venue1, aBoolean: true)
do {
let _ = try tournamentsRef.addDocument(from: newTournament)
} catch {
print (error)
}
}
总而言之,snapshot.toObjects()
无法开箱即用地反序列化非基元。
通过使用 @Parcelize
或 @Serializable
注释枚举,这将在后台生成代码,因此它知道如何为您的自定义 class 执行此操作。两者都需要 gradle 依赖项,分别是 org.jetbrains.kotlin.plugin.parcelize
和 org.jetbrains.kotlinx:kotlinx-serialization
。
对于枚举,例如:
enum class Venues (val nickname: String) {
Venue1 ("Venue 1"),
Venue2 ("Venue 2")
}
如果没有特别定义,nickname
不使用。 Venue1
将被序列化,Venue1
。
我定义了以下内容:
enum class Venues (val nickname: String) {
Venue1 ("Venue 1"),
Venue2 ("Venue 2")
}
data class Tournament (var aString: String = "Title",
var aDate: Date = Date(),
var anInt: Int = 8,
var venue: Venues = Venues.Venue1,
var aBoolean: Boolean = true)
将 Tournament
写入 Firestore 的以下代码按预期工作:
fun createNewTournament(view: View) {
val teamCount = (8..24).random()
val venue: Venues = Venues.values().random()
val newTournament = Tournament("String", Date(), teamCount, venue, false)
tournamentsRef.add(newTournament)
.addOnSuccessListener { docRef -> Log.d ("ADD", "DocSnapShot has id: ${docRef.id}") }
.addOnFailureListener { e -> Log.w ("ADD", "Error adding document", e)}
}
查看 Firebase 控制台,我看到一个完整的 Tournament
文档,其中 venue
字段定义为 String
。
但是,当我尝试读取相同内容时,我的应用程序在 toObjects
行崩溃:
val tournamentsRef = FirebaseFirestore.getInstance().collection("tournaments")
var tournaments = ArrayList<Tournament>()
tournamentsRef.addSnapshotListener { snapshot, error ->
if (error != null) {
return@addSnapshotListener
}
// CRASH: this line crashes if enum is included
tournaments = snapshot!!.toObjects(Tournament::class.java) as ArrayList<Tournament>
}
如果我从 data class
中删除 venue
枚举,所有文档都被成功读取,但显然没有 venue
字段。
那么,如何将 enum
s 与 Firestore 一起使用,具体来说,我如何将传入的 String
转换为我的 enum
?
为了便于比较,这是我在此应用程序的 iOS 版本中使用的 Swift 代码:
enum Venues: String, CaseIterable, Codable {
case venue1 = "Venue 1"
case venue2 = "Venue 2"
}
struct Tournament: Codable {
var aString: String
var aDate: Date
var anInt: Int
var venue: Venues
var aBoolean: Bool
}
let tournamentsRef = Firestore.firestore().collection("tournaments")
var tournaments = [Tournament]()
tournamentsRef
.addSnapshotListener { querySnapshot, error in
guard let documents = querySnapshot?.documents else { return }
self.tournaments = documents.compactMap { document in
let tournament = try? document.data(as: Tournament.self)
return tournament
}
}
func createNewTournament() {
let newTournament = Tournament(aString: "String", aDate: Date(), anInt: 8, venue: Venues.venue1, aBoolean: true)
do {
let _ = try tournamentsRef.addDocument(from: newTournament)
} catch {
print (error)
}
}
总而言之,snapshot.toObjects()
无法开箱即用地反序列化非基元。
通过使用 @Parcelize
或 @Serializable
注释枚举,这将在后台生成代码,因此它知道如何为您的自定义 class 执行此操作。两者都需要 gradle 依赖项,分别是 org.jetbrains.kotlin.plugin.parcelize
和 org.jetbrains.kotlinx:kotlinx-serialization
。
对于枚举,例如:
enum class Venues (val nickname: String) {
Venue1 ("Venue 1"),
Venue2 ("Venue 2")
}
如果没有特别定义,nickname
不使用。 Venue1
将被序列化,Venue1
。