【问题标题】:How to parse objects that has a sealed class param in kotlin android development using Room?如何使用 Room 在 kotlin android 开发中解析具有密封类参数的对象?
【发布时间】:2022-01-26 23:46:14
【问题描述】:

我有一个 Plant 数据类,它有一个 PlantType 密封类参数。 我正在使用 Room 本地数据库,但是当我尝试解析它时它失败了。它适用于具有可初始化类参数的其他类。

提前感谢您的帮助。

错误:
java.lang.RuntimeException:无法调用没有参数的私有 com.tenyitamas.mylittlegarden.domain.util.PlantType()

在 com.tenyitamas.mylittlegarden.data.util.Converters.fromPlantsJson(Converters.kt:99)

// 注释:Converters.kt: 99 是我包含的 Converters 代码的 from json 部分。

Plant.kt:

data class Plant(
    val type: PlantType,
    val upgrades: Upgrades
)

PlantType.kt:

sealed class PlantType {

    object Carrot : PlantType()
    object Tomato : PlantType()
    object Cucumber : PlantType()
    object Lettuce : PlantType()
    object Strawberry : PlantType()

    private companion object Constants {
        const val INITIAL_TIME_CARROT = 5_000L // 5s
        const val INITIAL_TIME_TOMATO = 6_000L
        const val INITIAL_TIME_CUCUMBER = 7_000L
        const val INITIAL_TIME_LETTUCE = 8_000L
        const val INITIAL_TIME_STRAWBERRY = 9_000L

        const val INITIAL_COST_CARROT = 10
        const val INITIAL_COST_TOMATO = 100
        const val INITIAL_COST_CUCUMBER = 1_000
        const val INITIAL_COST_LETTUCE = 10_000
        const val INITIAL_COST_STRAWBERRY = 100_000

        const val INITIAL_INCOME_CARROT = 10
        const val INITIAL_INCOME_TOMATO = 100
        const val INITIAL_INCOME_CUCUMBER = 1_000
        const val INITIAL_INCOME_LETTUCE = 10_000
        const val INITIAL_INCOME_STRAWBERRY = 100_000
    }

    val name: String
        get() {
            return when (this) {
                Carrot -> Resources.getSystem().getString(R.string.carrot)
                Tomato -> Resources.getSystem().getString(R.string.tomato)
                Cucumber -> Resources.getSystem().getString(R.string.cucumber)
                Lettuce -> Resources.getSystem().getString(R.string.lettuce)
                Strawberry -> Resources.getSystem().getString(R.string.strawberry)
            }
        }

    val image: Bitmap
        get() {
            return when (this) {
                Carrot -> {
                    BitmapFactory.decodeResource(Resources.getSystem(), R.drawable.ic_carrot)
                }
                Tomato -> {
                    BitmapFactory.decodeResource(Resources.getSystem(), R.drawable.ic_tomato)
                }
                Cucumber -> {
                    BitmapFactory.decodeResource(Resources.getSystem(), R.drawable.ic_cucumber)
                }
                Lettuce -> {
                    BitmapFactory.decodeResource(Resources.getSystem(), R.drawable.ic_lettuce)
                }
                Strawberry -> {
                    BitmapFactory.decodeResource(Resources.getSystem(), R.drawable.ic_strawberry)
                }
            }
        }

    val initialTime: Long
        get() {
            return when (this) {
                Carrot -> INITIAL_TIME_CARROT
                Tomato -> INITIAL_TIME_TOMATO
                Cucumber -> INITIAL_TIME_CUCUMBER
                Lettuce -> INITIAL_TIME_LETTUCE
                Strawberry -> INITIAL_TIME_STRAWBERRY
            }
        }

    val initialCost: Int
        get() {
            return when (this) {
                Carrot -> INITIAL_COST_CARROT
                Tomato -> INITIAL_COST_TOMATO
                Cucumber -> INITIAL_COST_CUCUMBER
                Lettuce -> INITIAL_COST_LETTUCE
                Strawberry -> INITIAL_COST_STRAWBERRY
            }
        }

    val initialIncome: Int
        get() {
            return when (this) {
                Carrot ->   INITIAL_INCOME_CARROT
                Tomato ->   INITIAL_INCOME_TOMATO
                Cucumber -> INITIAL_INCOME_CUCUMBER
                Lettuce ->  INITIAL_INCOME_LETTUCE
                Strawberry -> INITIAL_INCOME_STRAWBERRY
            }
        }
}

Converters.kt

@TypeConverter
    fun fromPlantsJson(json: String): List<Plant> {
        return jsonParser.fromJson<ArrayList<Plant>>(
            json,
            object : TypeToken<ArrayList<Plant>>(){}.type
        ) ?: emptyList()
    }

    @TypeConverter
    fun toPlantsJson(plants: List<Plant>): String {
        return jsonParser.toJson(
            plants,
            object : TypeToken<ArrayList<Plant>>(){}.type
        ) ?: "[]"
    }

【问题讨论】:

    标签: android json kotlin parsing android-room


    【解决方案1】:

    你的 PlantType 密封类里面只有对象。您可以为此使用枚举。

    enum class PlantType {
        Carrot, Tomato, Cucumber, Lettuce,  Strawberry
    }
    

    您的jsonParser 很可能能够序列化此枚举。

    编辑:在您编辑的问题中,您刚刚在PlantType 类中添加了一些新的vals,所有这些都有自定义getter,其返回值取决于PlantType。您仍然可以将其替换为枚举并将这些 vals 作为扩展名放在 PlantType 上。

    例如,

    enum class PlantType {
        Carrot, Tomato, Cucumber, Lettuce,  Strawberry
    }
    
    val PlantType.name: String
            get() {
                return when (this) {
                    Carrot -> Resources.getSystem().getString(R.string.carrot)
                    Tomato -> Resources.getSystem().getString(R.string.tomato)
                    Cucumber -> Resources.getSystem().getString(R.string.cucumber)
                    Lettuce -> Resources.getSystem().getString(R.string.lettuce)
                    Strawberry -> Resources.getSystem().getString(R.string.strawberry)
                }
            }
    

    【讨论】:

    • 我和其他密封班级的学生一起编辑了原始帖子
    • 我已经编辑了答案。看看它是否符合您的要求。
    • 非常感谢,我会尝试并回复您。但乍一看,这可能是解决方案:)
    • 好的,非常感谢。这就是解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多