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

如何在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原生序列化,需完成以下步骤:

  1. 给所有嵌套数据类添加@Serializable注解:
@Serializable
data class Commentary(...)

@Serializable
data class Translation(...)

@Serializable
data class ChapterSlokItem(...)
  1. 创建基于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)
    }
}
  1. 在build.gradle中添加序列化依赖:
plugins {
    id 'kotlinx-serialization'
}

dependencies {
    implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0"
}

内容的提问来源于stack exchange,提问作者Jemish Khunt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 07:08:15