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
相关产品推荐
相关产品推荐

