如何在Android Room存储含嵌套List的复杂数据?解决转换器缺失报错
问题:Room存储嵌套List复杂数据时类型转换器缺失报错
我在数据库中创建了两个无关联的独立表,希望在Android Room中存储包含List的复杂数据,且该List的元素还包含嵌套List<sub_data>。但运行时出现如下报错:
Unable to create application com.practice.gita.GitaApplication: java.lang.IllegalArgumentException: A required type converter (class com.practice.gita.Converters.Converters) for com.practice.gita.db.ChapterSummaryDAO is missing in the database configuration.
现有代码
实体类
ChapterSlok类
@Entity(tableName = "slok") data class ChapterSlok( @PrimaryKey val chapter_id: Int, val slokList: List<ChapterSlokItem> )
ChapterSlokItem类
data class ChapterSlokItem( val chapter_number: Int, val commentaries: List<Commentary>, val id: Int, val slug: String, val text: String, val translations: List<Translation>, val transliteration: String, val verse_number: Int, val word_meanings: String )
Commentary类
data class Commentary( val author_name: String, val description: String, val id: Int, val language: String )
Translation类
data class Translation( val author_name: String, val description: String, val id: Int, val language: String )
DAO接口
@Dao interface ChapterSummaryDAO { @Insert(onConflict = OnConflictStrategy.IGNORE) suspend fun addChapterSummary(chapters: List<ChapterSummaryItem>) @Query("SELECT * FROM chapter") suspend fun getChapterSummary(): List<ChapterSummaryItem> @Insert(onConflict = OnConflictStrategy.IGNORE) suspend fun addChapterSlok(slok: ChapterSlok) @Query("SELECT * FROM slok") suspend fun getChapterSlok(): List<ChapterSlok> }
数据库类
@Database(entities = [ChapterSummaryItem::class, ChapterSlok::class], version = 1) @TypeConverters(Converters::class) abstract class ChapterSummaryDataBase : RoomDatabase() { abstract val chapterSummaryDAO: ChapterSummaryDAO companion object { @Volatile private var INSTANCE: ChapterSummaryDataBase? = null fun getDataBase(context: Context): ChapterSummaryDataBase { if (INSTANCE == null) { synchronized(this) { INSTANCE = Room.databaseBuilder( context, ChapterSummaryDataBase::class.java, "chapterDB" ).build() } } return INSTANCE!! } } }
类型转换器类
@ProvidedTypeConverter class Converters { val gson = Gson() @TypeConverter fun fromCommentariesList(commentaries: List<Commentary>): String { return gson.toJson(commentaries) } @TypeConverter fun toCommentariesList(commentariesString: String): List<Commentary> { val type = object : TypeToken<List<Commentary>>() {}.type return gson.fromJson(commentariesString, type) } @TypeConverter fun fromTranslationsList(translations: List<Translation>): String { return gson.toJson(translations) } @TypeConverter fun toTranslationsList(translationsString: String): List<Translation> { val type = object : TypeToken<List<Translation>>() {}.type return gson.fromJson(translationsString, type) } @TypeConverter fun fromChapterSlokItemList(slokList: List<ChapterSlokItem>): String { return gson.toJson(slokList) } @TypeConverter fun toChapterSlokItemList(chapterSlokString: String): List<ChapterSlokItem> { val type = object : TypeToken<List<ChapterSlokItem>>() {}.type return gson.fromJson(chapterSlokString, type) } }
解决方案
错误核心原因
报错的本质是@ProvidedTypeConverter注解的使用逻辑错误:添加该注解后,Room不会自动实例化转换器类,需要手动传入实例;但当前代码既用了该注解,又没有手动注入实例,导致Room找不到所需转换器。
修复方案一:移除@ProvidedTypeConverter,让Room自动管理
直接删除转换器类上的@ProvidedTypeConverter注解,Room会自动创建Converters实例并使用:
class Converters { val gson = Gson() @TypeConverter fun fromCommentariesList(commentaries: List<Commentary>): String { return gson.toJson(commentaries) } @TypeConverter fun toCommentariesList(commentariesString: String): List<Commentary> { val type = object : TypeToken<List<Commentary>>() {}.type return gson.fromJson(commentariesString, type) } @TypeConverter fun fromTranslationsList(translations: List<Translation>): String { return gson.toJson(translations) } @TypeConverter fun toTranslationsList(translationsString: String): List<Translation> { val type = object : TypeToken<List<Translation>>() {}.type return gson.fromJson(translationsString, type) } @TypeConverter fun fromChapterSlokItemList(slokList: List<ChapterSlokItem>): String { return gson.toJson(slokList) } @TypeConverter fun toChapterSlokItemList(chapterSlokString: String): List<ChapterSlokItem> { val type = object : TypeToken<List<ChapterSlokItem>>() {}.type return gson.fromJson(chapterSlokString, type) } }
修复方案二:保留@ProvidedTypeConverter,手动注入实例
如果需要保留@ProvidedTypeConverter(比如转换器需要依赖其他对象),则需要在数据库构建时手动传入Converters实例:
修改数据库类的getDataBase方法:
fun getDataBase(context: Context): ChapterSummaryDataBase { if (INSTANCE == null) { synchronized(this) { INSTANCE = Room.databaseBuilder( context, ChapterSummaryDataBase::class.java, "chapterDB" ) .addTypeConverter(Converters()) // 手动添加转换器实例 .build() } } return INSTANCE!! }
可选方案:使用@Serializable替代Gson转换器
如果想用Kotlin原生序列化,需完成以下步骤:
- 给所有嵌套数据类添加
@Serializable注解:
@Serializable data class Commentary(...) @Serializable data class Translation(...) @Serializable data class ChapterSlokItem(...)
- 创建基于kotlinx.serialization的转换器:
import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json class Converters { private val json = Json { ignoreUnknownKeys = true } @TypeConverter fun fromChapterSlokItemList(slokList: List<ChapterSlokItem>): String { return json.encodeToString(slokList) } @TypeConverter fun toChapterSlokItemList(chapterSlokString: String): List<ChapterSlokItem> { return json.decodeFromString(chapterSlokString) } @TypeConverter fun fromCommentariesList(commentaries: List<Commentary>): String { return json.encodeToString(commentaries) } @TypeConverter fun toCommentariesList(commentariesString: String): List<Commentary> { return json.decodeFromString(commentariesString) } @TypeConverter fun fromTranslationsList(translations: List<Translation>): String { return json.encodeToString(translations) } @TypeConverter fun toTranslationsList(translationsString: String): List<Translation> { return json.decodeFromString(translationsString) } }
- 在build.gradle中添加序列化依赖:
plugins { id 'kotlinx-serialization' } dependencies { implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0" }
内容的提问来源于stack exchange,提问作者Jemish Khunt
相关产品推荐
相关产品推荐

