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

Android Room嵌套JSON存储报错:需添加类型转换器解决字段存储问题

解决Android Room存储嵌套JSON数据的报错问题

报错Cannot figure out how to save this field into database. You can consider adding a type converter for it的核心原因是:Room默认只支持存储基本数据类型(String、Int、Boolean等)或标记为@Entity的实体类,而你代码中的title、content是自定义嵌套对象,Room无法直接识别和存储它们。

解决方法是通过TypeConverter(类型转换器),将嵌套对象与数据库支持的String类型互相转换(把对象序列化为JSON字符串存储,读取时再反序列化为对象)。

步骤1:添加Gson依赖(若未添加)

在模块级build.gradle的dependencies中添加Gson依赖,用于JSON序列化/反序列化:

implementation 'com.google.code.gson:gson:2.10.1'

步骤2:创建TypeConverter类

新建类实现嵌套对象与String的互转逻辑:

import com.google.gson.Gson
import com.google.gson.reflect.TypeToken

class Converters {
    private val gson = Gson()

    // 将Title对象转为String
    @androidx.room.TypeConverter
    fun titleToString(title: Title?): String? {
        return title?.let { gson.toJson(it) }
    }

    // 将String转为Title对象
    @androidx.room.TypeConverter
    fun stringToTitle(json: String?): Title? {
        val type = object : TypeToken<Title>() {}.type
        return json?.let { gson.fromJson(it, type) }
    }

    // 将Content对象转为String
    @androidx.room.TypeConverter
    fun contentToString(content: Content?): String? {
        return content?.let { gson.toJson(it) }
    }

    // 将String转为Content对象
    @androidx.room.TypeConverter
    fun stringToContent(json: String?): Content? {
        val type = object : TypeToken<Content>() {}.type
        return json?.let { gson.fromJson(it, type) }
    }
}

步骤3:修正实体类问题

title、content不是Room实体,无需@PrimaryKey和@ColumnInfo注解,同时调整类名首字母大写(符合Kotlin命名规范):

@Entity(tableName = "icerik")
data class Icerik(
    @ColumnInfo(name = "title")
    @SerializedName("title")
    val baslik: Title?,
    @ColumnInfo(name = "content")
    @SerializedName("content")
    val icerik: Content?,
    @ColumnInfo(name = "date")
    @SerializedName("date")
    val tarih: String?,
    @ColumnInfo(name = "jetpack_featured_media_url")
    @SerializedName("jetpack_featured_media_url")
    val gorsel: String?
) {
    @PrimaryKey(autoGenerate = true)
    var uuid: Int = 0
}

data class Content(
    @SerializedName("rendered")
    val content: String?,
    @SerializedName("protected")
    val bool: Boolean?
)

data class Title(
    @SerializedName("rendered")
    val ytitle: String?
)

步骤4:在Database类中注册TypeConverter

在IcerikDatabase类上添加@TypeConverters注解,让Room识别转换器:

@Database(entities = [Icerik::class], version = 1)
@TypeConverters(Converters::class) // 注册转换器
abstract class IcerikDatabase : RoomDatabase() {
    abstract fun icerikDao(): IcerikDAO

    companion object {
        @Volatile private var instance: IcerikDatabase? = null
        private val lock = Any()

        operator fun invoke(context: Context) = instance ?: synchronized(lock) {
            instance ?: databaseOlustur(context).also { instance = it }
        }

        private fun databaseOlustur(context: Context) = Room.databaseBuilder(
            context.applicationContext,
            IcerikDatabase::class.java,
            "icerikdatabase"
        ).build()
    }
}

验证逻辑

完成修改后,Room会自动在存储Icerik对象时,将baslik(Title类型)和icerik(Content类型)转为JSON字符串存入数据库;读取时再自动转换为对应对象,即可解决报错并实现嵌套JSON的存储。

内容的提问来源于stack exchange,提问作者Kerim Berkay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 22:56:29