#android #firebase #kotlin #google-cloud-firestore #gson
#Android #firebase #kotlin #google-облако-firestore #gson
Вопрос:
Я работаю над приложением для Android, которое использует Firebase Firestore в качестве базы данных. Я пытаюсь сохранить список элементов SOLDITEM, где каждый элемент soldItem имеет PrescriptionType, сформированный из закрытых классов.
data class SoldItem(var itemName : String = "",
var quantity : String = "",
var totalPrice : Int = 0,
var itemQuantityType: ItemQuantityType = ItemQuantityType.SINGLE,
var prescriptionType: String = ""
) : Serializable
prescriptionType, определенный как строка, изначально является закрытым классом PrescriptionType
sealed class PrescriptionType : Parcelable {
// Check how to parcelize objects
@Parcelize
data class Syrup(var quantityInMls : Double = 2.5, var frequency : PrescriptionFrequency = PrescriptionFrequency.Stat, var time : PrescriptionTime = PrescriptionTime.OneDay) : PrescriptionType()
@Parcelize
data class Lotion(var frequency : PrescriptionFrequency = PrescriptionFrequency.Stat, var time : PrescriptionTime = PrescriptionTime.OneDay): PrescriptionType()
@Parcelize
data class Capsule(var quantity : Int = 1, var frequency : PrescriptionFrequency = PrescriptionFrequency.Stat, var time : PrescriptionTime = PrescriptionTime.OneDay ) : PrescriptionType()}
Я сохраняю prescriptionType в виде строки из-за отсутствия поддержки в FirebaseFirestore Android SDK непосредственно для закрытых классов. Мне пришлось создать свой собственный TypeConverter. Это довольно хорошо работает при генерации строки (JSON) из каждого prescriptionType, а также при генерации prescriptionType из строки.
@JvmStatic
@TypeConverter
fun fromPrescription(prescriptionType: PrescriptionType) : String{
val prescriptionAdapterFactory : RuntimeTypeAdapterFactory<PrescriptionType> = RuntimeTypeAdapterFactory.
of(PrescriptionType::class.java, "type")
.registerSubtype(PrescriptionType.Syrup::class.java, "Syrup")
.registerSubtype(PrescriptionType.Lotion::class.java, "Lotion")
.registerSubtype(PrescriptionType.Capsule::class.java, "Capsule")
val gsonBuilder = GsonBuilder().registerTypeAdapterFactory(prescriptionAdapterFactory).create()
return """ gsonBuilder.toJson(prescriptionType, PrescriptionType::class.java) """
}
@JvmStatic
@TypeConverter
fun toPrescriptionType(prescriptionType : String) : PrescriptionType {
val prescriptionAdapterFactory : RuntimeTypeAdapterFactory<PrescriptionType> = RuntimeTypeAdapterFactory.
of(PrescriptionType::class.java, "type")
.registerSubtype(PrescriptionType.Syrup::class.java, "Syrup")
.registerSubtype(PrescriptionType.Lotion::class.java, "Lotion")
.registerSubtype(PrescriptionType.Capsule::class.java, "Capsule")
val gsonBuilder = GsonBuilder().registerTypeAdapterFactory(prescriptionAdapterFactory).create()
return gsonBuilder.fromJson(prescriptionType, PrescriptionType::class.java)
}
}
Сохранение строки в базе данных работает довольно хорошо. Объект сохранен, и все в порядке — мы видим, что prescriptionType представляет собой строку.
Однако при извлечении soldItems в Firebase мы сталкиваемся с проблемой, когда кажется, что firebase SDK возвращает строку JSON и преобразует ее в объект и, следовательно, выходит из строя, поскольку prescriptionType — это строка, а не объект.
val soldItemsType = object : TypeToken<List<SoldItem>>() {}.type
val soldItemsFromBackend = it.get("soldItems").toString()
Timber.d(soldItemsFromBackend)
val soldItems = Gson().fromJson<List<SoldItem>>(
soldItemsFromBackend,
soldItemsType
)
Регистрация soldItemsFromBackend дает
[{drugQuantityType=SINGLE, prescriptionType={"type":"Capsule","frequency":"Stat","quantity":1,"time":"OneDay"}, itemName=Docusate, quantity=2, totalPrice=0}]
и попытка создать soldItems с использованием Gson выдает ошибку
Caused by: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 46 path $[0].prescriptionType
Я думаю, что Gson хочет проанализировать prescriptionType как строку, но вместо этого видит объект. Я пытался дополнить строку prescriptionType дополнительными кавычками, но это все равно не сработало.
Кто-нибудь, пожалуйста, знает, как я могу получить prescriptionType в виде строки?
Комментарии:
1.
val soldItemsFromBackend = it.get("soldItems").toString()
выглядит довольно сомнительно. В случае, еслиget(...)
возвращает вамList
, то вызовtoString()
для него вообще не дает действительного JSON. Таким образом, Firestore, скорее всего, правильно возвращает строку, но затем вашtoString()
вызов вызываетString.toString()
forprescriptionType
, который просто опускает кавычки. Вместо этого вам, вероятно, следует выполнить итерацию по элементам SoldItem и применять Gson только к ихprescriptionType
строке JSON.2. @Marcono1234, спасибо за ваш комментарий. it.get(…) фактически не возвращает список в этом экземпляре. Он возвращает тип Any?. Пожалуйста, вы знаете, как я могу получить soldItems в виде списка SoldItems?
3. Разве вы не можете просто привести ее, поскольку, по-видимому, во время выполнения это список? Кроме того, какой тип
it
имеет, или, скорее, какой методit.get(...)
? Этоcom.google.firebase.firestore.Query.get(...)
?