Qual è l'intento dei metodi getItem e getItemId nella classe Android BaseAdapter?


155

Sono curioso dello scopo dei metodi getIteme getItemIddella classe Adapter nell'SDK Android.

Dalla descrizione, sembra che getItemdovrebbe restituire i dati sottostanti. Quindi, se ho una matrice di nomi ["cat","dog","red"]e creo un adattatore ausando quello, allora a.getItem(1)dovrebbe restituire "cane", giusto? Cosa dovrebbe a.getItemId(1)tornare?

Se in pratica hai utilizzato questi metodi, potresti fornire un esempio?


16
+1 Ottima domanda. Voglio sottolineare che getItemId()in ArrayAdapter()sempre ritorna -1conassert false : "TODO"; return -1;
RDS

Risposte:


86

Vedo questi metodi come un approccio più pulito per accedere ai dati del mio elenco. Invece di accedere direttamente al mio oggetto adattatore tramite qualcosa di simile myListData.get(position)posso semplicemente chiamare l'adattatore come adapter.get(position).

Lo stesso vale per getItemId. Di solito userei questo metodo quando voglio eseguire alcune attività in base all'ID univoco di un oggetto nell'elenco. Ciò è particolarmente utile quando si lavora con un database. Il reso idpotrebbe essere un riferimento a un oggetto nel database sul quale potrei quindi eseguire diverse operazioni (aggiornamento / eliminazione / ecc.).

Quindi, invece di accedere all'ID dall'oggetto dati non elaborati come myListData.get(position).getId()è possibile utilizzare adapter.getItemId(position).

Un esempio di dove mi sentivo di dover usare questi metodi era in un progetto che utilizzava SeparatedListViewAdapter . Questo adattatore può contenere diversi tipi di adattatori, ognuno dei quali rappresenta dati di un tipo diverso (in genere). Quando si chiama getItem(position)il SeparatedListViewAdapter, l'oggetto restituito può essere diverso a seconda di quale "sezione" la posizione è che lo si invia.

Ad esempio, se si ha 2 sezioni nella vostra lista (frutta e caramelle): Se è stato utilizzato getItem(position)e positioncapitato di essere su un elemento nella frutta sezione, che avrebbe ricevuto un oggetto diverso se richiesto getItem(position)con positionpunta a un elemento della caramelle sezione. È quindi possibile restituire una sorta di valore ID costante in getItemId(position)cui rappresenta il tipo di dati getItem(position)restituiti oppure utilizzare instanceofper determinare quale oggetto si possiede.

A parte quello che ho menzionato, non mi sono mai sentito come se avessi davvero bisogno di usare questi metodi


7
per adattatori non sql correlati, getItemId avrà ancora uno scopo? in tal caso, cosa dovrebbe essere restituito? posizione?
sviluppatore Android il

1
lo scopo o l'uso del metodo dipende principalmente dallo sviluppatore e non è legato a un'app basata su database. usalo a tuo vantaggio per creare codice chiaro / leggibile / riutilizzabile.
James,

1
Sì, credo. getView, getCount, getViewTypeCount, Ecc sono utilizzati appositamente per mostrare correttamente l'interfaccia utente ListView. le altre funzioni semplicemente aiutano a creare implementare altre funzionalità come eseguire ulteriori azioni facendo clic su un elemento, ecc. anche se uso spesso getItemdentrogetView
james

1
@NicolasZozol Certo: è sicuro non implementare getItemId, semplicemente tornare 0Lo nullnon utilizzarlo da nessuna parte. Non vedo alcun motivo ovvio per cui un UUID sarebbe più prezioso di un semplice longvalore per ID. Modalità disconnessa? Cos'è quello?
Giacomo

1
@binnyb: Nicolas voleva dire che con gli UUID è ancora possibile creare ID univoci validi (ad es. sul proprio dispositivo mobile), anche senza una connessione di rete.
Levita,

32

Bene, sembra che questa domanda possa essere risolta in un modo più semplice e diretto ... :-)

In poche parole, Android ti consente di allegare longa qualsiasi ListViewelemento, è così semplice. Quando il sistema ti avvisa della selezione dell'utente, ricevi tre variabili identificative per dirti cosa è stato selezionato:

  • un riferimento alla vista stessa,
  • la sua posizione numerica nell'elenco,
  • questo longhai attaccato ai singoli elementi.

Sta a te decidere quale di questi tre è il più facile da gestire nel tuo caso particolare, ma hai tutti e tre tra cui scegliere in ogni momento. Pensa a questo longcome a un tag attaccato automaticamente all'elemento, solo che è ancora più semplice e facile da leggere.

L'incomprensione su ciò che di solito deriva da una semplice convenzione. Tutti gli adattatori devono fornire un getItemId()anche se in realtà non utilizzano questa terza identificazione. Quindi, per convenzione, quegli adattatori (inclusi molti negli esempi nell'SDK o in tutto il web) ritornano semplicemente positionper un solo motivo: è sempre unico. Tuttavia, se viene restituito un adattatore position, ciò significa che non desidera affatto utilizzare questa funzione, poiché positionè già noto, comunque.

Quindi, se devi restituire qualsiasi altro valore che ritieni opportuno, sentiti libero di farlo:

@Override
public long getItemId(int position) {
  return data.get(position).Id;
}

1
Bella spiegazione per questo getItemId()... Cosa succede quando / se questo metodo non viene ignorato nell'adattatore personalizzato?
dentex,

Essendo contrassegnato come astratto nella classe base, devi farlo. A meno che tu non abbia la precedenza su qualcosa che sostituisce l'adattatore originale, ovviamente. Prova a lasciarlo fuori, e se Eclipse si lamenta, devi farlo. :-)
Gábor

Grazie. Ho sempre avuto questo metodo commentato senza avvertimenti. Ho un CustomAdapter estende ArrayAdapter <CustomListItem> con getCount (), getItem (...) e getView (...), usando il "modello di supporto". Solo per curiosità ...
dentice

Sì, puoi farlo perché ArrayAdapter estende BaseAdapter e fornisce già la propria implementazione.
Gábor,

E con un array semplice, va bene. Ma basta considerare un altro caso, ad esempio quando si desidera visualizzare elementi da un database. Probabilmente estendi BaseAdapter e puoi usare questo ID lungo per memorizzare la chiave del database. Quando l'utente seleziona qualcosa, riceverai direttamente la chiave del record selezionato tramite l' argomento id . È quindi possibile caricarlo immediatamente dal database, ad esempio. L'unico problema è che devi usare i tasti numerici perché Android ha optato per un lungo invece di qualcosa di più ampio.
Gábor,

6

Il getItemIdmetodo è ampiamente progettato per funzionare con cursori supportati da database SQLite. Restituirà il campo ID del cursore sottostante per l'elemento in posizione 1.

Nel tuo caso non esiste un ID per l'elemento in posizione 1: suppongo che l'implementazione di ArrayAdapter restituisca solo -1 o 0.

EDIT: in realtà, restituisce solo la posizione: in questo caso 1.


2
No, ritorna -1. Ecco l'implementazioneassert false : "TODO"; return -1;
rd

5
A partire da Android 4.1.1, restituisce la posizione: grepcode.com/file/repository.grepcode.com/java/ext/…
emmby

4

Vorrei menzionare che dopo l'implementazione getIteme getItemIdpuoi usare ListView.getItemAtPosition e ListView.getItemIdAtPosition per accedere direttamente ai tuoi dati, invece di passare attraverso l'adattatore. Ciò può essere particolarmente utile quando si implementa un listener onClick.


3
Questo è davvero estremamente utile se hai un'intestazione nella tua lista e le posizioni passate al gestore di clic sono disattivate di una
entropia

4

Se implementato getItemIdcorrettamente, potrebbe essere molto utile.

Esempio :

Hai un elenco di album:

class Album{
     String coverUrl;
     String title;
}

E implementate getItemIdcosì:

@Override
public long getItemId(int position){
    Album album = mListOfAlbums.get(position);
    return (album.coverUrl + album.title).hashcode();
}

Ora l'id del tuo articolo dipende dai valori di coverUrl e dei campi del titolo e se cambi quindi e chiami notifyDataSetChanged()il tuo adattatore, l'adattatore chiamerà il metodo getItemId () di ogni elemento e aggiornerà solo gli articoli del proprietario che id è cambiato.

Questo è molto utile se stai facendo delle operazioni "pesanti" nel tuo getView().

A proposito: se vuoi che funzioni, devi assicurarti che il tuo hasStableIds()metodo restituisca false;


Questa è un'osservazione preziosa, puoi fornire alcuni dati per supportare questo meccanismo di aggiornamento selettivo?
Jaime Agudo,

Perché dovrebbe hasStableIds()restituire false? Mi sembra che l'hashcode calcolato dalla stessa stringa restituirebbe sempre lo stesso valore, che è un ID stabile secondo i documenti .
Big McLargeHuge

considera che l'uso di hashCode può restituire true a due stringhe
htafoya,

2

getItemo getItemIdsono pochi metodi principalmente progettati per allegare dati con elementi nell'elenco. In getItemtal caso , è possibile passare qualsiasi oggetto che verrà associato all'elemento nell'elenco. Normalmente le persone ritornano null. getItemIdè un longvalore univoco che è possibile allegare con lo stesso elemento nell'elenco. Le persone generalmente restituiscono la posizione nell'elenco.

Come si usa. Bene, poiché questi valori sono associati all'elemento nell'elenco, è possibile estrarli quando l'utente fa clic sull'elemento. Questi valori sono accessibili tramite AdapterViewmetodi.

// template class to create list item objects
class MyListItem{
    public String name;
    public long dbId;

    public MyListItem(String name, long dbId){
        this.name = name;
        this.dbId = dbId;
    }
}

///////////////////////////////////////////////////////////

// create ArrayList of MyListItem
ArrayList<MyListItem> myListItems = new ArrayList<MyListItem>(10);

// override BaseAdapter methods
@Override
public Object getItem(int position) {
    // return actual object <MyListItem>
    // which will be available with item in ListView
    return myListItems.get(position);
}

@Override
public long getItemId(int position) {
    // return id of database document object
    return myListItems.get(position).dbId;
}

///////////////////////////////////////////////////////////

// on list item click, get name and database document id
my_list_view.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

        // extract item data
        MyListItem selectedItem = (MyListItem)parent.getItemAtPosition(position);      
        System.out.println("Your name is : " + selectedItem.name);

        // extract database ref id
        long dbId = id;

        // or you could also use
        long dbId = parent.getItemIdAtPosition(position);
    }
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.