Android Room 无法识别 List 的 TypeConverer

Per*_*qin 5 android kotlin android-room

这是我的实体:

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

这是转换器:

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

        @JvmStatic
        @TypeConverter
        fun byteArrayToChanges(bytes: ByteArray): List<DbChange> {
            ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

但是编译器仍然抱怨:

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;
Run Code Online (Sandbox Code Playgroud)

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

Mic*_*ran 3

这实际上是 Kotlin 的错,而不是 Room 的错。
正如您在错误消息中看到的那样,您得到的List<? extends DbChange>List<DbChange>forchanges字段,因此 Room 尝试查找TypeConvertersforbyte[] -> List<? extends DbChange>List<? extends DbChange> -> byte[],但未能成功。

这是因为changesToByteArray方法参数类型生成为List<? extends DbChange>方法的类型byteArrayToChanges仍然是List<DbChange>,因此您会收到编译错误。

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

解决方案 1:
使用 Annotate类,以便为字段及其 setter生成不带通配符的类型:@JvmSuppressWildcards
Commitchanges

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

    @ColumnInfo(name = "changes", typeAffinity = ColumnInfo.BLOB)
    var changes: List<DbChange>
)
Run Code Online (Sandbox Code Playgroud)

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

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

        @JvmStatic
        @TypeConverter
        fun byteArrayToChanges(bytes: ByteArray): List<DbChange> {
            ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

data class DbChanges(val list: List<DbChange>)
Run Code Online (Sandbox Code Playgroud)

然后更新Commit类:

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

    @ColumnInfo(name = "changes", typeAffinity = ColumnInfo.BLOB)
    var changes: DbChanges
)
Run Code Online (Sandbox Code Playgroud)

并写新的TypeConverters

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

        @JvmStatic
        @TypeConverter
        fun byteArrayToChanges(bytes: ByteArray): DbChanges {
            ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)