【问题标题】:Android Room cannot recognize TypeConverer for ListAndroid Room 无法识别 List 的 TypeConverter
【发布时间】:2018-03-19 08:43:16
【问题描述】:

这是我的实体:

@Entity(tableName = "commits")
data class Commit(
        @PrimaryKey
        @ColumnInfo(name = "hash")
        val hash: String,
        @ColumnInfo(name = "changes", typeAffinity = ColumnInfo.BLOB)
        var changes: List<DbChange>
)

这是转换器:

class Converters {
    companion object {
        @JvmStatic
        @TypeConverter
        fun changesToByteArray(changes: List<DbChange>): ByteArray {
            ...
        }

        @JvmStatic
        @TypeConverter
        fun byteArrayToChanges(bytes: ByteArray): List<DbChange> {
            ...
        }
    }
}

而且我已经在注释中添加了 Converters 类:

@Database(entities = [Commit::class], version = 1)
@TypeConverters(Converters::class)
abstract class AppRoomDatabase : RoomDatabase() {
    ...
}

但是编译器还是报错:

e: /home/perqin/workspaces/cent-budget/cent-budget/app/build/tmp/kapt3/stubs/eaDebug/com/perqin/centbudget/data/sync/commit/Commit.java:20: error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
    private java.util.List<? extends com.perqin.centbudget.data.sync.changes.DbChange> changes;

如何解决这个问题?我一点想法都没有……

【问题讨论】:

  • 你只需要访问这个博客:bignerdranch.com/blog/room-data-storage-for-everyone
  • @pRaNaY 不,我不希望 DbChange 成为实体。实际上 DbChange 是一个接口,我需要根据实现手动对其进行序列化和反序列化。
  • 您是否尝试过@Ignore 来避免您遇到的编译器错误? @Ignore var changes: List&lt;DbChange&gt;
  • @pRaNaY @Ignore 可能不是我想要的,因为我确实需要将序列化的changes 存储到数据库中。
  • 我很好奇,如果将List 更改为MutableList 会发生什么?

标签: android kotlin android-room


【解决方案1】:

这实际上是 Kotlin 的错,而不是 Room 的错。
正如您在错误消息中看到的那样,对于 changes 字段,您得到的是 List&lt;? extends DbChange&gt; 而不是 List&lt;DbChange&gt;,因此 Room 试图为 byte[] -&gt; List&lt;? extends DbChange&gt;List&lt;? extends DbChange&gt; -&gt; byte[] 找到 TypeConverters,但没有这样做。

这是因为changesToByteArray方法的参数类型生成为List&lt;? extends DbChange&gt;但是byteArrayToChanges方法的类型仍然是List&lt;DbChange&gt;,因此会出现编译错误。

如果您想阅读更多内容,我会推荐 this 文章。

解决方案 1:
使用@JvmSuppressWildcards
注释 Commit 类,以便为 changes 字段生成不带通配符的类型,它是 setter:

@Entity(tableName = "commits")
@JvmSuppressWildcards
data class Commit(
    @PrimaryKey
    @ColumnInfo(name = "hash")
    val hash: String,

    @ColumnInfo(name = "changes", typeAffinity = ColumnInfo.BLOB)
    var changes: List<DbChange>
)

出于同样的原因注释List的类型:

class Converters {
    companion object {
        @JvmStatic
        @TypeConverter
        fun changesToByteArray(changes: List<@JvmSuppressWildcards DbChange>): ByteArray {
            ...
        }

        @JvmStatic
        @TypeConverter
        fun byteArrayToChanges(bytes: ByteArray): List<DbChange> {
            ...
        }
    }
}

解决方案 2:
为您的列表创建包装类,例如:

data class DbChanges(val list: List<DbChange>)

然后更新Commit类:

@Entity(tableName = "commits")
data class Commit(
    @PrimaryKey
    @ColumnInfo(name = "hash")
    val hash: String,

    @ColumnInfo(name = "changes", typeAffinity = ColumnInfo.BLOB)
    var changes: DbChanges
)

写新的TypeConverters:

class Converters {
    companion object {
        @JvmStatic
        @TypeConverter
        fun changesToByteArray(changes: DbChanges): ByteArray {
            ...
        }

        @JvmStatic
        @TypeConverter
        fun byteArrayToChanges(bytes: ByteArray): DbChanges {
            ...
        }
    }
}

【讨论】:

    猜你喜欢
    • 2018-03-28
    • 1970-01-01
    • 2018-01-18
    • 1970-01-01
    • 1970-01-01
    • 2021-11-24
    • 2018-12-28
    • 1970-01-01
    • 2023-03-09
    相关资源
    最近更新 更多