2010-03-30 9 views
33

Io di solito tendono a definire il livello di modello delle mie applicazioni utilizzando POJO di, come ad esempio l'articolo, commento, eccPOJO di rispetto cursori in Android

Stavo per implementare un AlphabetIndexer l'adattatore di uno dei miei ListViews. In questo momento questo adattatore accetta una raccolta di articoli, che normalmente ottengo dal mio wrapper attorno a un SQLiteDatabase.

La firma del constructer AlphabetIndexer è la seguente:

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

Dal momento che questo non accetta una Collection o qualcosa di simile, solo un cursore, mi è arrivato a chiedersi: oggetti forse non dovrebbe essere la creazione di per il mio modello, e basta usare i cursori restituiti dal database?

Quindi la domanda è, suppongo: cosa devo fare, rappresentare i dati con le raccolte di POJO o semplicemente lavorare con i cursori in tutta la mia app?

Qualsiasi input?

+0

Volete utilizzare i cursori forniti da un lib? Vedi: http://stackoverflow.com/questions/4285398/would-you-like-to-integrate-a-pojo-or-cursor-based-library-in-your-android-app – OneWorld

+0

Sto facendo qualcosa di simile QUI http://stackoverflow.com/questions/10224233/alphabetindexer-with-custom-adapter-managed-by-loadermanager – toobsco42

risposta

13

Ho incontrato problemi simili. In questo momento, mi sto prendendo cura dei POJO. Si noti, tuttavia, che è possibile creare la propria interfaccia Cursor per una raccolta di POJO, se lo si desidera.

+1

Lo so, ma sembra un po 'circolare ... creando un cursore per una raccolta creata da un cursore. :) – benvd

+1

Oh, nessuna domanda. Questo è uno dei motivi per cui tendo i POJO e lasciando le cose solo in "Cursori". In termini MVC, si finisce con modelli stupidi e controller intelligenti. – CommonsWare

+4

Ho deciso di accettare questa come risposta, poiché ora utilizzo questo approccio. Nello specifico, ho creato una classe interna pubblica nel mio 'SQLiteOpenHelper' per ogni tabella che ha. Quelle classi contengono un sacco di metodi per impedirmi di fare confusione con nomi di colonne o numeri. La differenza di prestazioni è immediatamente evidente in "ListView" con poche decine di voci. Inoltre, sembra preferire 'CursorAdapters' a' BaseAdapters'. Ho ottenuto l'ispirazione per questo dai tuoi libri (in particolare pagina 102 in Android Tutorials 2.9), che non avevo indietro quando ho fatto questa domanda, quindi grazie! :-) – benvd

9

Un voto per oggetti entità (POJO). Passare i cursori in giro, soprattutto per il livello dell'interfaccia utente, mi sembra così sbagliato (indipendentemente dal fatto che il tipo di sdk di Android implichi di farlo in questo modo). Di solito ci sono molti modi per popolare l'interfaccia utente e io tendo ad evitare quelli che usano direttamente i cursori. Ad esempio, per popolare le mie visualizzazioni elenco personalizzato, utilizzo un oggetto SimpleAdapter e offro agli oggetti della mia raccolta la possibilità di restituire una rappresentazione di se stessi come List<? extends Map<String, ?>> per il costruttore di SimpleAdapter.

Io uso un modello in cui ogni tabella è avvolta da un oggetto entità e ha una classe provider che gestisce le mie operazioni CRUD associate a tale entità. Facoltativamente, se ho bisogno di funzionalità estese per le raccolte, le avvolgo anch'io (ad esempio, EntityItems extends ArrayList<EntityItem>). Il provider ha una classe base che passo un riferimento a una classe DbAdapter che esegue il pesante sollevamento attorno al db.

La ragione principale, diverso da preferenze personali, è che voglio nascondere questo tipo di codice il più lontano dal mio UI possibile:

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

Se vedo che tipo di codice inline nell'interfaccia utente strato, di solito mi aspetto di vedere molto peggio in agguato dietro l'angolo. Forse ho passato troppo tempo nel mondo aziendale a lavorare su grandi team, ma preferisco la leggibilità a meno che non ci sia un problema di prestazioni legittime o se si tratta di un'attività abbastanza piccola in cui l'espressività è solo un'impresa eccessiva.

+4

"Uso un SimpleAdapter e offro agli oggetti della mia collezione la possibilità di restituire una rappresentazione di se stessi come elenco > per il costruttore di SimpleAdapter" - che implica un sacco di copia dei dati, che mastica il tempo della CPU e generando spazzatura. Questo può o non può importare per qualsiasi app. – CommonsWare

+0

Teniamo d'occhio cose del genere, e memorizzo i risultati di questo tipo di chiamate in modo da non pensare che il mio uso di una funzione di comodità come questa possa incorrere in una memoria significativa o in una hit della CPU. Questo fa sorgere una domanda che forse puoi rispondere comunque. Se popolo una HashMap e tutte le mie chiavi sono stringhe di stringa inizializzate e tutti i miei valori sono proprietà stringa di oggetti inizializzati, chiamando map.put (chiave, valore) non sto semplicemente passando attorno a puntatori invece di creare una tonnellata di nuovi oggetti (spazzatura)? Assumerei così, da non so Java abbastanza bene da rispondere per conto mio. – Rich

+2

Hey Rich. Mi piace anche l'approccio di avere l'interfaccia utente agnostica da dove provengono i dati, e il codice dei cursori nell'interfaccia utente mi sembra brutto, ma posso trovare un paio di motivi per cui sono necessari. Innanzitutto, sono il modo più efficace per collegare i dati a cose come ListView. In secondo luogo, per convertire in una raccolta devi scorrere linearmente il cursore, O (n), creare un oggetto per riga che non faresti nel cursore, e il GC dovrà raccoglierli a un certo punto, ma soprattutto , stai caricando l'intera raccolta in memoria.I cursori tengono solo la riga corrente. – palako

12

Mi piace creare classi POJO supportate da cursore. Una classe POJO cursore-backed ha un costruttore che prende un cursore e offre i seguenti vantaggi:

  • Facile da usare getter che restituiscono il tipo di contenuto corretto, molto meglio di ottenere indici e di dover ricordare il tipo di dati nella banca dati
  • Metodi Getter che calcolano i loro risultati da altri getter, proprio come la programmazione OO dovrebbe essere
  • I valori di ritorno Getter possono essere enumerati!

Questi pochi vantaggi valgono un po 'di codice, molti bug sono stati evitati ora che gli ingegneri utenti non accedono direttamente alle colonne del cursore. Usiamo ancora la classe CursorAdapter, ma la prima riga nel metodo bindView è creare il POJO con il cursore dal Cursore e da quel momento il codice è bello.

Di seguito è un esempio di implementazione, è uno snap per i tecnici utenti di trasformare un cursore opaco in oggetto utente chiaramente definito, da quel punto in cui può essere passato intorno e acceduto proprio come un normale POJO fintanto che il cursore di supporto non è chiuso SmartUserCursor è una classe speciale che ho scritto per assicurarmi che la posizione del cursore sia ricordata e ripristinata prima che il cursore sia accessibile e memorizza anche gli indici delle colonne del cursore in modo che le ricerche siano veloci.

ESEMPIO:

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

} 
+0

qualsiasi codice di esempio? Inoltre è più lento dal momento che devi caricare tutti i dati dai cursori negli oggetti del modello? – marchinram

+0

Non carico tutti i dati dal cursore. Ho solo un gruppo di getter che accedono al cursore internamente. Pubblicherò un esempio più tardi. – satur9nine

+0

cool, grazie, ad esempio, attualmente uso greendao che penso faccia qualcosa di simile ma sarebbe bello vedere un esempio di come funziona – marchinram

2

risposte sono 4 anni. Penso che ora abbiamo abbastanza potenza della CPU per farcela con più cose. La mia idea sarebbe di lavorare solo con POJOs e ArrayList; ed estendendo CursorLoader per mappare il cursore su POJOs in background e consegnare l'arraylist all'attività;

a meno che tu sei interroga centinaia di righe, ma poi, quante volte ci fai che contro gentilezza di usare POJO, getter e setter