Room自定义对象列表TypeConverter失效问题求助
问题分析与解决方案
核心问题
错误java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY的本质是:Room在解析查询返回的emaps字段时,误用了单个Emap的TypeConverter去解析JSON数组格式的字符串,导致Gson无法将数组转换为单个对象。
具体修复步骤
1. 移除冲突的TypeConverter方法
你的Converters类同时包含List<Emap>和单个Emap的转换逻辑,这会让Room无法正确判断使用哪一个转换器。保留列表转换方法,移除单个对象的转换逻辑(除非你有单独存储单个Emap的业务需求):
class Converters { @TypeConverter fun fromEmapListToString(emaps: List<Emap>): String { return GsonBuilder().create().toJson(emaps) } @TypeConverter fun fromStringtoEmapList(emapsString: String): List<Emap> { val listType = object : TypeToken<List<Emap>>(){}.type return GsonBuilder().create().fromJson(emapsString, listType) } }
2. 统一TypeConverter作用范围
避免同时在字段和数据库全局配置转换器,移除UserEmaps实体中emaps字段上的@field:TypeConverters注解,保留Database类上的全局配置即可:
@Entity(tableName = "emaps_users") data class UserEmaps( @PrimaryKey(autoGenerate = false) val userId : Int, // 移除字段上的TypeConverters注解 val emaps : List<Emap> )
3. 优化查询方式(更稳妥的方案)
建议查询完整的UserEmaps实体,再从中提取emaps列表,而不是直接查询单个字段。这样Room会严格按照实体定义的转换器规则处理数据:
@Query("SELECT * FROM emaps_users WHERE userId = :userId LIMIT 1") suspend fun getUserEmaps(userId : Int) : UserEmaps?
使用时的调用逻辑:
val userEmaps = dao.getUserEmaps(userId) val emapsList = userEmaps?.emaps ?: emptyList()
4. 升级数据库版本(关键)
由于修改了TypeConverter逻辑,需要升级数据库版本号,确保Room重新处理数据转换规则,避免旧数据解析异常:
@Database( entities = [ User::class, Term::class, Emap::class, Page::class, PageIndex::class, Incidencia::class, Emap.Poi::class, UserEmaps::class, CuadernoDeViaje::class ], version = 3, // 版本号从2升级为3 exportSchema = false ) @TypeConverters(Converters::class) abstract class CanaryDatabase : RoomDatabase()
内容的提问来源于stack exchange,提问作者Danwolve
相关产品推荐
相关产品推荐

