34 votes

POJO et curseurs dans Android

J'ai généralement tendance à définir la couche modèle de mes applications en utilisant des POJO, tels que Article, Commentaire, etc.

J'étais sur le point d'implémenter un AlphabetIndexer dans l'adaptateur d'une de mes ListViews. Actuellement, cet adaptateur accepte une collection d'articles, que j'obtiens normalement de mon enveloppe autour d'une SQLiteDatabase.

La signature du constructeur de l'AlphabetIndexer est la suivante :

public AlphabetIndexer (Cursor cursor, int sortedColumnIndex, CharSequence alphabet)

Puisque cela n'accepte pas une collection ou quelque chose de similaire, juste un curseur, je me suis demandé : peut-être que je ne devrais pas créer d'objets pour mon modèle, et juste utiliser les curseurs retournés par la base de données ?

Ainsi, le question Je me demande ce que je dois faire : représenter les données avec des collections de POJO, ou simplement travailler avec des curseurs dans toute mon application ?

Un avis ?

13voto

CommonsWare Points 402670

J'ai rencontré des problèmes similaires. Pour l'instant, je m'éloigne des POJO. Notez cependant que vous pouvez créer vos propres objets de type Cursor pour une collection de POJO, si vous le souhaitez.

12voto

satur9nine Points 3901

J'aime créer des classes POJO adossées à un curseur. Une classe POJO adossée à un curseur possède un constructeur qui prend un curseur et offre les avantages suivants :

  • Des récupérateurs faciles à utiliser qui renvoient le bon type de contenu, ce qui est bien mieux que d'obtenir des index et de devoir se souvenir du type de données dans la base de données
  • Des méthodes gâchettes qui calculent leurs résultats à partir d'autres gâchettes, comme le veut la programmation OO.
  • Les valeurs de retour des getter peuvent être des enums !

Ces quelques avantages valent bien un peu de code passe-partout, de nombreux bogues ont été évités maintenant que les ingénieurs utilisateurs n'accèdent pas eux-mêmes aux colonnes du curseur. Nous utilisons toujours la classe CursorAdapter, mais la première ligne de la méthode bindView consiste à créer le POJO soutenu par le curseur à partir du curseur et à partir de là, le code est magnifique.

Ci-dessous un exemple d'implémentation, c'est un jeu d'enfant pour les ingénieurs utilisateurs de transformer un curseur opaque en un objet User clairement défini, à partir duquel il peut être transmis et accédé comme un POJO normal tant que le curseur n'est pas fermé. Le SmartUserCursor est une classe spéciale que j'ai écrite pour m'assurer que la position du curseur est mémorisée et restaurée avant l'accès au curseur. Elle stocke également les index des colonnes du curseur afin que les recherches soient rapides.

EXEMPLE :

public class User {

    private final SmartUserCursor mCursor;

    public User(SmartUserCursor cursor, int position) {
        mCursor = new SmartUserCursor(cursor, position);
    }

    public long getUserId() {
        return mCursor.getLong(SmartUserCursor.Columns.userId);
    }

    public UserType getType() {
        return UserType.valueOf(mCursor.getString(SmartUserCursor.Columns.type));
    }

    public String getFirstName() {
        return mCursor.getString(SmartUserCursor.Columns.firstName);
    }

    public String getLastName() {
        return mCursor.getString(SmartUserCursor.Columns.lastName);
    }

    public final String getFullName() {
        return getFirstName() + " " + getLastName();
    }

    public static User newUserFromAdapter(BaseAdapter adapter, int position) {
        return new User((SmartUserCursor)adapter.getItem(position), position);
    }

    public static User newUserBlocking(Context context, long UserId) {
        Cursor cursor = context.getContentResolver().query(
                Users.CONTENT_URI_CLIENT,
                Users.DEFAULT_USER_PROJECTION,
                Users.Columns.USER_ID+"=?",
                new String[] {String.valueOf(UserId)},
                null
        );

        if (cursor == null || !cursor.moveToFirst()) {
            throw new RuntimeException("No User with id " + UserId + " exists");
        }

        return new User(new SmartUserCursor(cursor, Users.DEFAULT_USER_PROJECTION), -1);
    }

    public final void closeBackingCursor() {
        mCursor.close();
    }

}

9voto

Rich Points 16818

Un vote pour les objets entités (POJOs). Faire circuler des curseurs, en particulier dans la couche d'interface utilisateur, me semble une erreur (que le SDK d'Android implique ou non de le faire de cette manière). Il y a généralement plusieurs façons de remplir votre interface utilisateur, et j'ai tendance à éviter celles qui utilisent directement des curseurs. Par exemple, pour alimenter mes vues de liste personnalisées, j'utilise un SimpleAdapter et je donne à mes objets de collection la possibilité de retourner une représentation d'eux-mêmes en tant que List<? extends Map<String, ?>> pour le constructeur de SimpleAdapter.

J'utilise un modèle où chaque table est enveloppée par un objet entité et possède une classe fournisseur qui gère mes opérations CRUD associées à cette entité. Si j'ai besoin d'une fonctionnalité étendue pour les collections, je les enveloppe également (par ex. EntityItems extends ArrayList<EntityItem> ) Le fournisseur a une classe de base à laquelle je passe une référence à une classe DbAdapter qui fait le gros travail autour de la base de données.

La principale raison, hormis les préférences personnelles, est que je veux cacher ce type de code aussi loin que possible de mon interface utilisateur :

String something = cursor.getString(cursor.getColumnIndex(COLUMN_NAME_CONSTANT));

Si je vois ce genre de code en ligne dans la couche d'interface utilisateur, je m'attends généralement à voir des choses bien pires se cacher dans le coin. J'ai peut-être passé trop de temps dans le monde de l'entreprise à travailler avec de grandes équipes, mais je privilégie la lisibilité, à moins qu'il n'y ait un problème de performance légitime ou qu'il s'agisse d'une tâche suffisamment petite pour que l'expressivité ne soit qu'une surcharge pour l'entreprise.

2voto

urSus Points 2583

Les réponses ont 4 ans. Je pense que maintenant nous avons assez de puissance CPU pour nous en sortir avec plus de choses. Mon idée serait de ne travailler qu'avec des POJO et des ArrayLists ; et d'étendre le CursorLoader pour faire correspondre le curseur aux POJO en arrière-plan et fournir les ArrayLists à l'activité ;

à moins que vous ne demandiez des centaines de lignes, mais alors, combien de fois le faites-vous par rapport à la commodité d'utiliser des POJO, des getters et des setters ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X