Android Room error: TypeConverter not recognised for List of Enums
Android Room error: TypeConverter not recognised for List of Enums
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()) }
}
}
我在我的数据库 class 中这样设置:
@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<DayOfWeek>
(并在 DayOfWeekConverter
中对 ArrayList
进行更改)然后一切工作正常。如果有人能帮我解决这个问题并告诉我如何在这里使用 List
,那将很有帮助,这让我发疯:/。
我们无法存储和获取没有数组列表的列表枚举。房间不支持。但是如果你想避免使用数组列表,你可以创建一个对象 ListDayOfWeek with List 是一个属性。我试过了,没问题。如果您需要代码,请在这里回复。我会post它。
你不应该把它像那样存储到你的数据库中。最好构建类似的东西并将其存储为 int:
enum class DaysOfWeek(var bitValue: Int) {
Monday(64),
Tuesday(32),
Wednesday(16),
Thursday(8),
Friday(4),
Saturday(2),
Sunday(1);
}
最后你的实用函数转换 from/to 枚举。
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"}
代码未经测试,因为我不在我的计算机上,但这应该显示了比存储枚举更好的概念(这只是预定义值的别名!)
出于某种原因,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
更改为不可空
List
在Kotlin中的完整签名是List<out E>
(Java中的List<? extend E>
),转换这样的泛型没有任何意义。换句话说,Room 不知道输入是 DayOfWeek
还是它的子类。
至于 ArrayList
和 MutableList
,它们的完整签名是 ArrayList<E>
和 MutableList<E>
相应地,输入类型是固定的,因此 Room 知道如何转换它。
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()) }
}
}
我在我的数据库 class 中这样设置:
@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<DayOfWeek>
(并在 DayOfWeekConverter
中对 ArrayList
进行更改)然后一切工作正常。如果有人能帮我解决这个问题并告诉我如何在这里使用 List
,那将很有帮助,这让我发疯:/。
我们无法存储和获取没有数组列表的列表枚举。房间不支持。但是如果你想避免使用数组列表,你可以创建一个对象 ListDayOfWeek with List 是一个属性。我试过了,没问题。如果您需要代码,请在这里回复。我会post它。
你不应该把它像那样存储到你的数据库中。最好构建类似的东西并将其存储为 int:
enum class DaysOfWeek(var bitValue: Int) {
Monday(64),
Tuesday(32),
Wednesday(16),
Thursday(8),
Friday(4),
Saturday(2),
Sunday(1);
}
最后你的实用函数转换 from/to 枚举。
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"}
代码未经测试,因为我不在我的计算机上,但这应该显示了比存储枚举更好的概念(这只是预定义值的别名!)
出于某种原因,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
更改为不可空
List
在Kotlin中的完整签名是List<out E>
(Java中的List<? extend E>
),转换这样的泛型没有任何意义。换句话说,Room 不知道输入是 DayOfWeek
还是它的子类。
至于 ArrayList
和 MutableList
,它们的完整签名是 ArrayList<E>
和 MutableList<E>
相应地,输入类型是固定的,因此 Room 知道如何转换它。