不支持将Kotlin密封类插入或检索到Room数据库中.枚举可以很容易地工作,但不是密封的类.下面是我的DOWNLOADSTATUS海豹示例

@Entity(tableName = "SomeTableName")
data class LibraryDownloadsEntity(
    @PrimaryKey
    val contentId: String,
    val contentURI: String? = EMPTY_STRING,
    val downloadDate: LocalDateTime? = null,
    val downloadStatus: LibraryEntityDownloadStatus = LibraryEntityDownloadStatus.NOTDOWNLOADED()
)

// This is an sealed class
sealed class ShareLibraryEntityDownloadStatus {
    class DOWNLOADING( val downloadProgress: Int) :
        ShareLibraryEntityDownloadStatus()

    class DOWNLOADED(val filePath: String) :
        ShareLibraryEntityDownloadStatus()

    class FAILED(val failureReason: DownloadFailureReason) :
        ShareLibraryEntityDownloadStatus()

    class NOTDOWNLOADED(): ShareLibraryEntityDownloadStatus()
}

在使用它时,我会得到如下编译时间错误 Cannot figure out how to save this field into database. You can consider adding a type converter for it. - downloadStatus in ... package

现在我使用了如下所示的类型转换器

    // Converters for DownloadStatus
    @TypeConverter
    fun downloadStatusToString(downloadStatus: ShareLibraryEntityDownloadStatus): String {
        return Gson().toJson(downloadStatus)
    }

    @TypeConverter
    fun downloadStatusFromString(json: String): ShareLibraryEntityDownloadStatus {
        return Gson().fromJson(json, ShareLibraryEntityDownloadStatus::class.java)
    }

这应该是可行的,但您将在运行时记住以下错误: java.lang.RuntimeException: Failed to invoke private "...somepackagename".downloads.LibraryEntityDownloadStatus() with no args

这说明密封类不能实例化是有道理的.关于如何将DownloadStatus信息存储到房间数据库有什么 idea 吗

推荐答案

我花了一些时间,这是正确的行为,密封的类不能实例化.解决方案基于密封类的子类可以实例化的思想工作. 类型转换器成功地从数据库中获取数据(数据库会将其传递给类型转换器),此时出现问题.

        return Gson().fromJson(json, LibraryEntityDownloadStatus::class.java)

GSON库无法实例化LibraryEntityDownloadStatus.但是,如果该信息可用,它可以实例化密封类的子类.所以我放了一个名为‘tag’的字段(对于每个子元素来说应该是唯一的),可以用来识别子元素的类型.

sealed class ShareLibraryEntityDownloadStatus(val tag: String) {
class DOWNLOADING(val downloadProgress: Int) :
    ShareLibraryEntityDownloadStatus(tag = "DOWNLOADING")

class DOWNLOADED(val filePath: String) :
    ShareLibraryEntityDownloadStatus(tag = "DOWNLOADED")

class FAILED(val failureReason: DownloadFailureReason) :
    ShareLibraryEntityDownloadStatus(tag = "FAILED")

class NOTDOWNLOADED : ShareLibraryEntityDownloadStatus(tag = "NOTDOWNLOADED")}

并对类型转换器进行如下更改.

@TypeConverter
fun downloadStatusToString(downloadStatus: LibraryEntityDownloadStatus): String {
    return Gson().toJson(downloadStatus)
}

@TypeConverter
fun downloadStatusFromString(json: String): LibraryEntityDownloadStatus {
    var output : LibraryEntityDownloadStatus = LibraryEntityDownloadStatus.NOTDOWNLOADED()
    val obj = JsonParser.parseString(json).asJsonObject
    when(obj["tag"].asString) {
        "NOTDOWNLOADED" -> output = LibraryEntityDownloadStatus.NOTDOWNLOADED()
        "DOWNLOADING" -> output = Gson().fromJson(json, LibraryEntityDownloadStatus.DOWNLOADING::class.java)
        "DOWNLOADED" -> output = Gson().fromJson(json, LibraryEntityDownloadStatus.DOWNLOADED::class.java)
        "DOWNLOADFAILED" -> output = Gson().fromJson(json, LibraryEntityDownloadStatus.FAILED::class.java)
    }
    return output
}

JsonParser和gson来自"Package com.google.gson;"

这显然奏效了,我们知道这是有充分理由的.这是最好的方法吗?让我知道哪种方法效果更好.

Android相关问答推荐

Android配置设置. gradle不同应用风格

滚动屏幕时更改按钮外观

对支持哪些数据存储区方法感到困惑

从惰性列中删除项目时Jetpack Compose崩溃

Play Google上发布的一款应用的房间数据库迁移

如何将.txtassets资源 转换为ArrayList<;字符串>;kotlin格式?

AndroidX Media3 迁移指南

如何将 Room Persistence 依赖项正确添加到我的 Jetack Compose Android 应用程序

为什么 Android Studio 中的 theme.xml 目录没有任何原色

retrofit2.HttpException: HTTP 401

更改当前活动并返回后,Android webview 滚动不起作用

单击按钮时不显示 Toast 消息

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

在 Jetpack Compose 中包装内容

Jetpack Compose Material3 禁用 ListItem

将房间中的实体更新为 isCompleted 并使用 Flow 问题获取所有数据

无法解析依赖项'com.github.smarteist:autoimageslider:1.4.0-appcompat'

Android Studio Emulator Internet 连接问题仅是第一次

react-native android项目未找到错误

使用 Android 字符串数组在 Room 中迁移