You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Room嵌套自定义对象列表转换:构造函数报错

解决Room错误:Entities and POJOs must have a usable public constructor

问题根源

你在Timer实体中对List<Interval>字段使用了@Embedded注解,这是错误的——Room的@Embedded仅支持嵌入单个实体/POJO对象,不支持集合类型。Room无法解析集合的嵌入逻辑,因此抛出构造器相关的错误。

修复步骤

1. 移除@Embedded注解

修改Timer实体,去掉timerIntervals字段上的@Embedded:

@Entity
data class Timer(
    // 保留其他原有字段
    val timerIntervals: List<Interval>,
    // 保留其他原有字段
) {
    constructor() : this(
        // 其他字段默认值
        timerIntervals = listOf(Interval()),
        // 其他字段默认值
    )
}

2. 补充Duration类型转换器

Room无法直接识别自定义的Duration类,必须为其添加序列化/反序列化转换器。更新你的Converters类:

class Converters {
    // 保留List<Interval>的转换器
    @TypeConverter
    fun fromIntervalList(intervals: List<Interval>): String {
        val gson = Gson()
        val type = object : TypeToken<List<Interval>>() {}.type
        return gson.toJson(intervals, type)
    }

    @TypeConverter
    fun toIntervalList(intervals: String): List<Interval> {
        val gson = Gson()
        val type = object : TypeToken<List<Interval>>() {}.type
        return gson.fromJson(intervals, type)
    }

    // 添加Duration的转换器
    @TypeConverter
    fun fromDuration(duration: Duration): String {
        val gson = Gson()
        return gson.toJson(duration)
    }

    @TypeConverter
    fun toDuration(durationString: String): Duration {
        val gson = Gson()
        return gson.fromJson(durationString, Duration::class.java)
    }

    // 删除Timer相关的转换器(无需为实体类添加转换器)
}

3. 更新数据库版本

实体结构变更后,需升级数据库版本号:

@Database(
    entities = [User::class, Timer::class],
    version = 2 // 版本号从1升级为2
)
@TypeConverters(Converters::class)
abstract class SyncFitDatabase: RoomDatabase() {
    abstract val userDao: UserDao
    abstract val timerDao: TimerDao
}

4. 处理数据库迁移(开发阶段可选)

如果之前已运行过App,实体结构变更会触发Room迁移错误。开发阶段可通过以下方式快速解决:

// 在数据库构建器中添加销毁式迁移
Room.databaseBuilder(
    context.applicationContext,
    SyncFitDatabase::class.java,
    "sync_fit_db"
)
.fallbackToDestructiveMigration() // 清空旧数据,仅开发阶段使用
.build()

关键说明

  • @Embedded仅用于将单个对象的字段平铺到实体表中,集合类型必须通过类型转换器序列化为JSON字符串存储。
  • 所有自定义非基本类型(如Duration)都需要对应的类型转换器,Room无法自动解析这些类型。
  • 你的实体类已具备空构造器,符合Room要求,构造器本身不是问题所在。

内容的提问来源于stack exchange,提问作者Kyle Sharp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 10:17:47