android - 使用 Room 在 SQLite 中保存复杂的 JSON 响应

标签 android kotlin android-room

我正在尝试使用 Room 实现 JSON API 响应的缓存。
我在 JSON 中获得的响应遵循以下数据类结构:

@Serializable
data class ApiDataResponse(
    val success: Boolean,
    val message: String? = null,
    val albums: List<AlbumResponse> = emptyList()
)
@Serializable
data class AlbumResponse(
    val id: String,
    val title: String,
    val createdBy: String,
    val enabled: Boolean,
    val keywords: List<String>,
    val pics: List<PicResponse>
)
@Serializable
data class PicResponse(
    val picUrl: String,
    val emojis: List<String>
)

备注:

  • @Serializable 来自 kotlinx.serialization 库,用于解析 JSON 响应。
  • 这些响应数据类只在我的数据源层中使用, View 层不关心ApiDataResponse,只知道一个AlbumResponse 的“纯”版本称为 AlbumPicResponse 的“纯”版本称为 Pic(通过“纯” "我的意思是没有外部库注释的数据类)。

因此,为了使用 Room 实现此缓存,我可以丢弃 ApiDataResponse 并仅保存 AlbumResponse 的内容(以及随后的 PicResponse),为 Room entities 提供遵循此想法的新数据类:

@Entity(tableName = "albums")
data class AlbumEntity(
    @PrimaryKey(autoGenerate = false)
    val id: String,
    val title: String,
    val createdBy: String,
    val enabled: Boolean,
    val keywords: List<String>, // obstacle here
    val pics: List<PicEntity> // obstacle here
)
// obstacle here
// @Entity
data class PicEntity(
    val picUrl: String,
    val emojis: List<String>
)

我已经知道如何在 Room 中保存简单数据,使用最简单的 JSON 我能够完成这项任务,问题是在这个更复杂的场景中我不知道如何实现这个目标。所以我希望有人能在这种情况下指导我。

最佳答案

也许有点晚了,但我还是想补充一些关于 MikeT 的回答的有趣信息。

不需要创建一个新的数据类只是为了使用TypeConverter将自定义对象转换为JSON,例如:

@Entity(tableName = "albums")
data class AlbumEntity(
    @PrimaryKey(autoGenerate = false)
    val id: String,
    val title: String,
    val createdBy: String,
    val enabled: Boolean,
    val keywords: List<String>,
    val pics: List<PicEntity> // can be converted directly
)
import kotlinx.serialization.Serializable

@Serializable // to be able to do the serialize with the kotlinx.serialization
data class PicEntity(
    val picUrl: String,
    val emojis: List<String>
)

仅使用这两个数据类,我们就可以构建TypeConverters,如下所示:

import androidx.room.TypeConverter
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

class DatabaseConverter {
    private val json = Json

    @TypeConverter
    fun convertStringListToString(strings: List<String>): String =
        json.encodeToString(strings)

    @TypeConverter
    fun convertStringToStringList(string: String): List<String> =
        json.decodeFromString(string)

    @TypeConverter
    fun convertPicEntityListToString(picsEntity: List<PicEntity>): String =
        json.encodeToString(picsEntity)

    @TypeConverter
    fun convertStringToPicEntityList(string: String): List<PicEntity> =
        json.decodeFromString(string)
}

创建示例虚拟列表的代码:

object DummyAlbums {
    fun createList(): List<AlbumEntity> = listOf(
        AlbumEntity(
            id = "0001",
            title = "Album AB",
            createdBy = "Created by AB",
            enabled = true,
            keywords = listOf("ab"),
            pics = dummyPics(albumId = "0001", size = 0)
        ),
        AlbumEntity(
            id = "0002",
            title = "Album CD",
            createdBy = "Created by CD",
            enabled = false,
            keywords = listOf("cd", "c", "d"),
            pics = dummyPics(albumId = "0002", size = 1)
        ),
        AlbumEntity(
            id = "0003",
            title = "Album EF",
            createdBy = "Created by EF",
            enabled = true,
            keywords = listOf(),
            pics = dummyPics(albumId = "0003", size = 2)
        )
    )

    private fun dummyPics(
        albumId: String,
        size: Int
    ) = List(size = size) { index ->
        PicEntity(
            picUrl = "url.com/$albumId/${index + 1}",
            emojis = listOf(":)", "^^")
        )
    }
}

所以我们可以在表中有以下数据: table output

我想强调这个细节,因为对于某人来说,拥有一个包含最干净数据的表可能很重要。在更具体的情况下,要使其干净,您可以使用 Kotlin 函数手动进行转换,例如 joinToString()split()

关于android - 使用 Room 在 SQLite 中保存复杂的 JSON 响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73238344/

相关文章:

android - 在构建时下载 Android 字符串资源

android - 如何在 Jetpack Compose 中设置行宽等于 TextField 的宽度?

dependency-injection - 使用 Guice + Kotlin 绑定(bind)对象列表

android - 通过 Dagger 2 提供 RoomDatabase 时实现 .addCallback() 的正确方法是什么?

java - 有没有办法覆盖 Android Room 实体构造函数?

android - Eclipse SVN 在提交时卡住

android - 编译Facebook Android SDK示例应用程序时出错

android - 在外部单击时如何使用和关闭 PopupWindow?

java - 许多第三方库无法与 android studio bumblebee 更新一起使用

android - 如何在 Kotlin [Dagger-Hilt] 中创建和使用房间数据库