2017-06-12 2 views
8

Est-il possible d'utiliser un type Enum comme champ incorporé dans une classe Entity avec les nouveaux composants d'architecture Android et la bibliothèque de persistance de la pièce?Composants de l'architecture Android: utilisation des énumérations

Mon entité (avec Enum embedded):

@Entity(tableName = "tasks") 
public class Task extends SyncEntity { 

    @PrimaryKey(autoGenerate = true) 
    String taskId; 

    String title; 

    /** Status of the given task. 
    * Enumerated Values: 0 (Active), 1 (Inactive), 2 (Completed) 
    */ 
    @Embedded 
    Status status; 

    @TypeConverters(DateConverter.class) 
    Date startDate; 

    @TypeConverters(StatusConverter.class) 
    public enum Status { 
     ACTIVE(0), 
     INACTIVE(1), 
     COMPLETED(2); 

     private int code; 

     Status(int code) { 
      this.code = code; 
     } 

     public int getCode() { 
      return code; 
     } 
    } 
} 

Mon TypeConverter:

public class StatusConverter { 

    @TypeConverter 
    public static Task.Status toStatus(int status) { 
     if (status == ACTIVE.getCode()) { 
      return ACTIVE; 
     } else if (status == INACTIVE.getCode()) { 
      return INACTIVE; 
     } else if (status == COMPLETED.getCode()) { 
      return COMPLETED; 
     } else { 
      throw new IllegalArgumentException("Could not recognize status"); 
     } 
    } 

    @TypeConverter 
    public static Integer toInteger(Task.Status status) { 
     return status.getCode(); 
    } 
} 

Quand je compile ce je reçois une erreur disant « erreur: (52, 12) erreur: Entités et Pojos doit avoir un constructeur public utilisable. Vous pouvez avoir un constructeur vide ou un constructeur dont les paramètres correspondent aux champs (par nom et type). '

Mise à jour 1 Ma classe SyncEntity:

/** * classe de base pour toutes les entités de la chambre qui sont synchronisées. */

@Entity 
public class SyncEntity { 

    @ColumnInfo(name = "created_at") 
    Long createdAt; 

    @ColumnInfo(name = "updated_at") 
    Long updatedAt; 
} 
+0

Est-ce que 'SyncEntity' définissent les constructeurs? – CommonsWare

+0

Non, ce n'est pas le cas. Problème mis à jour avec SyncEntity.class. – Bohsen

+0

Je pense que vous devez soit rendre vos champs 'public', offrir des setters' public', ou offrir un constructeur 'public' qui correspond' vos colonnes '@ Query'. Sinon, Room ne peut pas vous fournir de données.Votre seul constructeur est le zéro argument. – CommonsWare

Répondre

13

je peux utiliser des valeurs ENUM à Room avec TypeConverters. Il y a quelques parties à changer à votre code:

1) Vous devez déclarer les champs de votre entité publique ou ils doivent avoir des getters/setters publics. Ou vous obtiendrez ci-dessous erreur:

yourField is not public in YourEntity; cannot be accessed from outside package

2) Vous n'avez pas besoin de l'annotation @Embedded pour votre champ status. C'est pour les objets imbriqués. More from docs.

3) Vous n'avez pas utilisé l'annotation @TypeConverters au bon endroit. Dans votre cas, il peut être défini au-dessus du champ status. More from docs.

4) Vous devez définir un constructeur pour votre entité ou vous obtiendrez ci-dessous erreur:

Entities and Pojos must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type).

Vous pouvez définir un constructeur vide pour ignorer cette erreur.

5) Utilisez int au lieu de Integer dans votre TypeConverter.

Somme; ci-dessous fonctionne comme prévu:

@Entity(tableName = "tasks") 
public class Task extends SyncEntity { 

    @PrimaryKey(autoGenerate = true) 
    public String taskId; 

    public String title; 

    /** Status of the given task. 
    * Enumerated Values: 0 (Active), 1 (Inactive), 2 (Completed) 
    */ 
    @TypeConverters(StatusConverter.class) 
    public Status status; 

    @TypeConverters(DateConverter.class) 
    public Date startDate; 

    // empty constructor 
    public Task() { 
    } 

    public enum Status { 
     ACTIVE(0), 
     INACTIVE(1), 
     COMPLETED(2); 

     private int code; 

     Status(int code) { 
      this.code = code; 
     } 

     public int getCode() { 
      return code; 
     } 
    } 
} 
+0

Merci @Devrim car il était "Utiliser int au lieu de Integer dans votre TypeConverter" –

+0

Si vous devez * utiliser * des valeurs entières pour vos énumérations, c'est la bonne façon de le faire. N'utilisez jamais l'ordinal. –

1

Pour simplifier:

public enum Status { 
    ACTIVE, 
    INACTIVE, 
    COMPLETED; 
} 

puis, vos convertisseurs:

@TypeConverter 
public static Task.Status toStatus(int ordinal) { 
    return Task.Status.values()[ordinal]; 
} 

@TypeConverter 
public static Integer toOrdinal(Task.Status status) { 
    return status.ordinal(); 
} 
+0

Fonctionne. Tous les tests passent. Merci beaucoup. – Bohsen

+3

Les ordinaux sont dangereux à utiliser, ils réduisent la quantité de code que vous écrivez mais toute modification au milieu ou au début peut provoquer des erreurs étranges dans votre code. Ceci n'est pas recommandé. –

+0

@AndrewT Alors, recommanderiez-vous de rétablir et d'utiliser le code original? – Bohsen