8

La bibliothèque de pièces ne reconnaît pas un TypeConverter que j'ai créé pour un List d'enums. Cependant, quand je change ceci en un ArrayList d'enums cela fonctionne bien. Quelqu'un a une idée de pourquoi et que puis-je faire pour que cela fonctionne avec List? (Utilisation de la liste dans Kotlin est plus facile et je ne veux vraiment pas être en train de convertir en avant et en arrière à ArrayList juste à cause de cela).Android Erreur de salle: TypeConverter non reconnu pour la liste des énumérations

Voici mon code:

Mon modèle:

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

DayOfWeek est un ENUM:

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] 
     } 

    } 

} 

Mon 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()) } 
    } 

} 

Une d Je l'ai mis dans ma classe de DB comme ceci:

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

    abstract fun exampleDao(): ExampleDao 

} 

Mon OAC ressemble à ceci:

@Dao 
interface ExampleDao { 

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

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

} 

L'erreur que je reçois avec ce code est:

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; 

Comme je l'ai dit ci-dessus, si je change la propriété days à ArrayList<DayOfWeek> (et apporter les modifications à ArrayList dans DayOfWeekConverter) alors tout fonctionne bien. Si quelqu'un peut m'aider à comprendre cela et me dire comment je peux utiliser List ici ce serait d'une grande aide, cela me rend fou: /.

+0

votre classe S'il vous plaît publier « ExampleDao ». –

+0

Le DAO ne semble pas pertinent pour le problème que j'ai avec @PravinDivraniya, mais je l'ai ajouté maintenant au cas où cela vous aiderait à comprendre le problème. À votre santé. – Franco

+1

Je suis tombé sur le même problème. Étant donné que, apparemment, ce n'est pas possible, j'ai créé une demande de fonctionnalité: https://issuetracker.google.com/issues/69164099 –

Répondre

1

Pour une raison quelconque, Chambre n'aime pas Kotlin List, mais quand je l'ai remplacé List avec MutableList il a commencé à travailler:

@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() 
    } 
} 

Ce n'est pas la solution parfaite, mais espérons que vous pouvez étudier plus avec cette.

vous devez également modifier @PrimaryKey ne pas être annulable

+0

Je crois me souvenir que je l'ai essayé et que ça n'a pas fonctionné, mais je ne suis pas sûr comme c'était il y a des mois. Si j'ai le temps, je pourrais essayer, mais je suis très occupé ATM donc je ne serai pas capable de le faire pendant un certain temps. Avez-vous essayé cela vous-même? – Franco

+0

J'ai finalement eu le temps de l'essayer et en effet cela a fonctionné avec 'MutableList' :), merci @ TomekPolański! En y réfléchissant, je suppose que c'est logique, car 'List's dans Kotlin sont immuables et donc vous ne pouvez pas leur ajouter de valeurs, ce qui est peut-être ce que Room essaye de faire en arrière-plan. – Franco

-1

Nous n'avons aucun moyen de stocker et d'obtenir une liste énumérer sans tableau. La chambre ne le supporte pas. Mais si vous voulez éviter d'utiliser la liste de tableau, vous pouvez créer un objet ListDayOfWeek avec List est un attribut. Je l'ai essayé et c'est ok. Si vous avez besoin de code, veuillez répondre ici. Je vais le poster.

+0

Pourriez-vous également poster un code pour d'autres lecteurs? – azizbekian

+0

J'étais déjà au courant de cette solution de contournement, mais je ne la trouve pas acceptable car elle n'est pas évolutive. Merci quand même. – Franco

-1

Vous ne devriez pas le stocker comme ça dans votre base de données. Mieux construire quelque chose comme ça et le stocker comme int:

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

Enfin, votre utilitaire fonctionne pour convertir de/à enum.

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 
    } 

Maintenant, vous pouvez soit stocker un int et obtenir les jours de la semaine plus tard:

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

ou vous utilisez le ENUM et écrire un TypeConverter approprié pour cela.

@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) } 
} 

Vous pouvez faire une boucle à travers le ENUM et obtenir tous les jours en utilisant

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

est non testé car je ne suis pas sur mon ordinateur, mais cela devrait montrer le concept qui fonctionne mieux que le stockage d'un ENUM (qui est juste un alias à une valeur prédéfinie!)

+0

Je pense que vous n'avez pas lu mon code ci-dessus, j'essaie déjà de le sauvegarder sous la forme d'une liste d'ints, pas d'enums, donc votre réponse ne résout pas mon problème. – Franco

+0

C'est pourquoi j'ai écrit un exemple de travail. Vous n'avez pas besoin d'une liste si vous le résolvez au niveau du bit. Essayez de comprendre mon code. C'est la bonne façon de stocker les jours de la semaine. –

+0

Je pense que je n'étais pas clair dans mon précédent commentaire, je le sauvegarde déjà sous forme de chaîne, qui est composée de la liste des entiers concaténés, n'essayant pas de sauvegarder la liste comme vous le pensez, tout est dans mon code au dessus. J'ai lu votre code mais je ne sais pas pourquoi le résoudre bitwise "est la bonne façon de stocker les jours de la semaine", je ne pense pas que c'est "le bon" moyen, c'est juste une autre solution différente de celle déjà utilisée . À la fin, ce que je veux n'est pas une autre solution de contournement, mais pour comprendre pourquoi cela ne fonctionne pas avec 'List' et s'il y a un moyen de l'utiliser sans avoir à ajouter du code supplémentaire. – Franco