【问题标题】:Android Room error: TypeConverter not recognised for List of EnumsAndroid Room 错误:枚举列表无法识别 TypeConverter
【发布时间】:2018-03-28 20:57:11
【问题描述】:

Room 库无法识别我为 List 的枚举创建的 TypeConverter。但是,当我将其更改为枚举的ArrayList 时,它可以正常工作。任何人都知道为什么以及我该怎么做才能使用List 进行这项工作? (在 Kotlin 中使用 List 更容易,我真的不想仅仅因为这个而转换为 ArrayList)。

这是我的代码:

我的模特:

@Entity
data class Example(@PrimaryKey val id: String?,
                   val name: String,
                   var days: List<DayOfWeek>?)

DayOfWeek 是一个枚举:

enum class DayOfWeek {

    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY;

    val value: Int
        get() = ordinal + 1


    companion object {

        private val ENUMS = DayOfWeek.values()

        fun of(dayOfWeek: Int): DayOfWeek {
            if (dayOfWeek < 1 || dayOfWeek > 7) {
                throw RuntimeException("Invalid value for DayOfWeek: " + dayOfWeek)
            }

            return ENUMS[dayOfWeek - 1]
        }

    }

}

我的TypeConverter

private const val SEPARATOR = ","

class DayOfWeekConverter {

    @TypeConverter
    fun daysOfWeekToString(daysOfWeek: List<DayOfWeek>?): String? {
        return daysOfWeek?.map { it.value }?.joinToString(separator = SEPARATOR)
    }

    @TypeConverter
    fun stringToDaysOfWeek(daysOfWeek: String?): List<DayOfWeek>? {
        return daysOfWeek?.split(SEPARATOR)?.map { DayOfWeek.of(it.toInt()) }
    }

}

我在我的数据库类中这样设置它:

@Database(entities = arrayOf(Example::class), version = 1)
@TypeConverters(DayOfWeekConverter::class)
abstract class AppDatabase : RoomDatabase() {

    abstract fun exampleDao(): ExampleDao

}

我的 DAO 如下所示:

@Dao
interface ExampleDao {

    @Query("SELECT * FROM example")
    fun getAll(): LiveData<List<Example>>

    @Insert(onConflict = REPLACE)
    fun save(examples: List<Example>)

}

我使用此代码得到的错误是:

error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
e: 

e:     private java.util.List<? extends com.example.DayOfWeek> days;

就像我上面所说的,如果我将days 属性更改为ArrayList&lt;DayOfWeek&gt;(并在DayOfWeekConverter 中更改ArrayList),那么一切正常。如果有人能帮我解决这个问题并告诉我如何在这里使用List,那将非常有帮助,它让我发疯:/。

【问题讨论】:

  • 请发布您的“ExampleDao”课程。
  • DAO 似乎与我遇到的@PravinDivraniya 问题无关,但我现在已经添加了它,以防它帮助您找出问题所在。干杯。
  • 我遇到了同样的问题。鉴于显然这是不可能的,我创建了一个功能请求:issuetracker.google.com/issues/69164099
  • @Franco,我已经更新了我的解决方案以使用 Room 进行编译
  • 谢谢@TomekPolański,我会在有时间的时候尝试测试它,如果我能验证它是否按预期工作,我会接受你的回答。

标签: android kotlin android-room android-architecture-components


【解决方案1】:

由于某种原因,Room 不喜欢 Kotlin List,但是当我将 List 替换为 MutableList 时,它开始工作了:

@Entity
data class Example(@PrimaryKey val id: String,
                   val name: String,
                   var days: MutableList<DayOfWeek>?)

class DayOfWeekConverter {
    companion object {

        @TypeConverter
        @JvmStatic
        fun daysOfWeekToString(daysOfWeek: MutableList<DayOfWeek>?): String? =
                daysOfWeek?.map { it.value }?.joinToString(separator = SEPARATOR)

        @TypeConverter
        @JvmStatic
        fun stringToDaysOfWeek(daysOfWeek: String?): MutableList<DayOfWeek>? =
                daysOfWeek?.split(SEPARATOR)?.map { DayOfWeek.of(it.toInt()) }?.toMutableList()
    }
}

这不是完美的解决方案,但希望您可以对此进行更多调查。

您还需要将@PrimaryKey 更改为不可为空

【讨论】:

  • 我似乎记得我试过了,但没有成功,但我不确定几个月前的情况。如果我有时间,我可能会尝试一下,但我很忙 atm,所以我暂时无法做到。你自己试过吗?
  • 我终于有时间尝试一下,确实它与MutableList 一起工作:),谢谢@TomekPolański!想一想,我想这是有道理的,因为 Kotlin 中的 Lists 是不可变的,因此您无法向它们添加值,这可能是 Room 在后台尝试做的事情。
  • 只是想补充一点,您还必须将 @Converters 注释添加到 ROOM DATABASE 中。我没有,它一直给我错误。另请参阅adrianhall.github.io/android/2018/08/08/…
【解决方案2】:

Kotlin 中List 的完整签名是List&lt;out E&gt;(Java 中为List&lt;? extend E&gt;),转换这种泛型类型没有任何意义。换句话说,Room 不知道输入是 DayOfWeek 还是它的子类。

对于ArrayListMutableList,它们的完整签名对应的是ArrayList&lt;E&gt;MutableList&lt;E&gt;,输入类型是固定的,因此Room知道如何转换它。

【讨论】:

    【解决方案3】:

    没有数组列表,我们无法存储和获取 List 枚举。房间不支持。但是如果你想避免使用数组列表,你可以创建一个对象 ListDayOfWeek ,其中 List 是一个属性。我试过了,没关系。如果您需要代码,请在此处回复。我会发的。

    【讨论】:

    • 我已经知道这种解决方法,但我认为它不可接受,因为它不可扩展。无论如何,谢谢。
    【解决方案4】:

    您不应该将它这样存储到您的数据库中。最好构建类似的东西并将其存储为 int:

    enum class DaysOfWeek(var bitValue: Int) {
        Monday(64),
        Tuesday(32),
        Wednesday(16),
        Thursday(8),
        Friday(4),
        Saturday(2),
        Sunday(1);
    }
    

    最后你的实用函数可以从枚举转换为枚举。

    fun daysToBitValue(days: EnumSet<DaysOfWeek>): Int {
            var daysBitValue = 0
            for (`val` in days) daysBitValue += `val`.bitValue
            return daysBitValue
    }
    
    
    private fun fromBitValues(origBitMask: Int): EnumSet<DaysOfWeek> {
    
            val ret_val = EnumSet.noneOf(DaysOfWeek::class.java)
    
            var bitMask = origBitMask
    
            for (`val` in DaysOfWeek.values()) {
                if (`val`.bitValue and bitMask == `val`.bitValue) {
                    bitMask = bitMask and `val`.bitValue.inv()
                    ret_val.add(`val`)
                }
            }
    
            if (bitMask != 0) {
                throw IllegalArgumentException(String.format(Locale.getDefault(), "Bit mask value 0x%X(%d) has unsupported bits 0x%X.  Extracted values: %s", origBitMask, origBitMask, bitMask, ret_val))
            }
    
            return ret_val
      }
    

    现在您可以存储一个 int 并在以后获取工作日:

    @Entity
    data class Example(@PrimaryKey val id: String?,
                       val name: String,
                       var days: Int = 0) 
    

    或者您使用枚举并为此编写适当的类型转换器。

    @Entity
    data class Example(@PrimaryKey val id: String?,
                       val name: String,
                       var days: EnumSet<DaysOfWeek>?) 
    
    
    class DayOfWeekConverter {
    
        @TypeConverter
        fun daysOfWeekToString(daysOfWeek: EnumSet<DayOfWeek>?) =
            daysOfWeek?.let{ YourUtilities.daysToBitValue(it) }
    
        @TypeConverter
        fun intToDaysOfWeek(daysOfWeek: Int?) = 
            daysOfWeek?.let {  YourUtilities.fromBitValues(it) } 
    }
    

    您可以遍历枚举并通过使用获取所有天数

    for (aDaysOfWeekEnumSet in daysOfWeekEnumSet) 
                 info{ "day = ${aDaysOfWeekEnumSet.name"} 
    

    代码未经测试,因为我不在我的计算机上,但这应该显示比存储枚举更好的概念(这只是预定义值的别名!)

    【讨论】:

    • 我认为您没有阅读我上面的代码,我已经尝试将其保存为整数列表,而不是枚举,因此您的回答没有解决我的问题。
    • 这就是为什么我写了一个工作示例。如果按位解决,则不需要列表。尝试理解我的代码。这是存储工作日的正确方式。
    • 我想我在之前的评论中并不清楚,我已经将它保存为一个字符串,它由串联的整数列表组成,而不是像你看起来那样保存列表本身想想,这一切都在我上面的代码中。我阅读了您的代码,但我不确定为什么按位解决它“是存储工作日的正确方法”,我认为这不是“正确”的方法,它只是与我已经使用的方法不同的另一种解决方法。最后,我想要的不是另一种解决方法,而是要了解为什么这不适用于List,以及是否有一种无需添加额外代码即可使用它的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-25
    • 2021-10-24
    • 2018-01-18
    • 2017-05-18
    • 1970-01-01
    • 2011-09-19
    相关资源
    最近更新 更多