Jaki jest cel metod getItem i getItemId w klasie BaseAdapter systemu Android?

155

Ciekawi mnie przeznaczenie metod getItemi getItemIdklasy Adapter w Android SDK.

Z opisu wynika, że getItempowinno zwrócić podstawowe dane. Tak więc, jeśli mam tablicę imion ["cat","dog","red"]i utworzę adapter aza pomocą tego, to a.getItem(1)powinienem zwrócić „pies”, prawda? Co powinno a.getItemId(1)wrócić?

Jeśli korzystałeś z tych metod w praktyce, czy możesz podać przykład?

oneporter
źródło
16
+1 Doskonałe pytanie. Chcę podkreślić, że getItemId()w ArrayAdapter()zawsze wraca -1zassert false : "TODO"; return -1;
RDS

Odpowiedzi:

86

Postrzegam te metody jako czystsze podejście do uzyskiwania dostępu do danych mojej listy. Zamiast bezpośredniego dostępu do mojego obiektu adaptera za pośrednictwem czegoś takiego, myListData.get(position)mogę po prostu wywołać adapter w stylu adapter.get(position).

To samo dotyczy getItemId. Zwykle używałbym tej metody, gdy chcę wykonać jakieś zadanie na podstawie unikalnego identyfikatora obiektu na liście. Jest to szczególnie przydatne podczas pracy z bazą danych. Zwrócony idmoże być odniesieniem do obiektu w bazie danych, na którym mógłbym następnie wykonać różne operacje (aktualizacja / usunięcie / itp.).

Zamiast więc uzyskiwać dostęp do identyfikatora z surowego obiektu danych, jak myListData.get(position).getId()możesz użyć adapter.getItemId(position).

Jednym z przykładów, w którym czułem, że muszę użyć tych metod, był projekt korzystający z SeparatedListViewAdapter . Ten adapter może zawierać wiele różnych rodzajów adapterów, z których każdy reprezentuje dane innego typu (zazwyczaj). Dzwoniąc getItem(position)na SeparatedListViewAdapter, obiekt zwrócony może być różny w zależności od „sekcja” sytuacja jest taka, że ty ją wysłać.

Na przykład, gdybyś miał 2 sekcje na swojej liście (owoce i cukierki): Jeśli użyłeś getItem(position)i przypadkowo znalazłeś positionsię na pozycji w sekcji owoców , otrzymasz inny przedmiot niż gdybyś poprosił getItem(position)o positionwskazanie przedmiotu w cukierku Sekcja. Możesz wtedy zwrócić jakąś stałą wartość identyfikatora, getItemId(position)która reprezentuje rodzaj zwracanych danych getItem(position), lub użyć jej instanceofdo określenia posiadanego obiektu.

Poza tym, o czym wspomniałem, nigdy nie czułem, że naprawdę potrzebuję tych metod

James
źródło
7
w przypadku adapterów niezwiązanych z sql, czy getItemId nadal będzie miało cel? jeśli tak, co należy zwrócić? pozycja?
programista Androida
1
cel lub użycie metody zależy głównie od programisty i nie jest związane z aplikacją opartą na bazie danych. użyj go na swoją korzyść, aby stworzyć przejrzysty / czytelny / wielokrotnego użytku kod.
James
1
Chyba tak. getView, getCount, getViewTypeCountItp są wykorzystywane specjalnie dla prawidłowo pokazując swoją listview UI. inne funkcje po prostu pomagają w tworzeniu implementacji innych funkcjonalności, takich jak wykonywanie dalszych czynności po kliknięciu elementu itp., chociaż często używam getItemwewnątrzgetView
james
1
@NicolasZozol Sure- jest to bezpieczne, aby nie wdrażać getItemId, po prostu zwróć 0Llub nullnigdzie nie używaj. Nie widzę żadnego oczywistego powodu, dla którego UUID miałby być cenniejszy niż tylko jakaś longwartość identyfikatora. Tryb rozłączony? Co to jest?
james
1
@binnyb: Nicolas miał na myśli, że dzięki UUID nadal możliwe jest tworzenie ważnych unikalnych identyfikatorów (np. na urządzeniu mobilnym), nawet bez połączenia z siecią.
Lewita
32

Cóż, wydaje się, że na to pytanie można odpowiedzieć w prostszy i bardziej bezpośredni sposób ... :-)

Mówiąc najprościej, Android umożliwia dołączenie longdo dowolnego ListViewelementu, to takie proste. Gdy system powiadomi Cię o wyborze użytkownika, otrzymasz trzy zmienne identyfikujące, aby poinformować Cię, co zostało wybrane:

  • odniesienie do samego widoku,
  • jego numeryczna pozycja na liście,
  • to longdołączyłeś do poszczególnych elementów.

Do Ciebie należy decyzja, który z tych trzech elementów jest dla Ciebie najłatwiejszy w Twoim konkretnym przypadku, ale cały czas masz do wyboru wszystkie trzy. Pomyśl o tym longjak o tagu automatycznie dołączonym do przedmiotu, tyle że jest jeszcze prostszy i łatwiejszy do odczytania.

Nieporozumienie co do tego, co zwykle robi, wynika z prostej konwencji. Wszystkie adaptery muszą zapewniać getItemId()nawet, jeśli w rzeczywistości nie używają tej trzeciej identyfikacji. Tak więc, zgodnie z konwencją, te adaptery (w tym wiele w przykładach w SDK lub w całej sieci) po prostu wracają positionz jednego powodu: są zawsze unikalne. Mimo to, jeśli adapter powróci position, to naprawdę oznacza, że nie chce w ogóle korzystać z tej funkcji, ponieważ i tak positionjest już znana.

Jeśli więc chcesz zwrócić inną wartość, którą uważasz za stosowną, możesz to zrobić:

@Override
public long getItemId(int position) {
  return data.get(position).Id;
}
Gábor
źródło
1
Niezłe wyjaśnienie tego getItemId()… Co się stanie, gdy / jeśli ta metoda nie zostanie zastąpiona w niestandardowym adapterze?
dentex
Będąc oznaczonym jako abstrakcyjne w klasie bazowej, musisz. O ile oczywiście nie zastąpisz czegoś, co zastępuje oryginalny adapter. Spróbuj to pominąć, a jeśli Eclipse narzeka, to musisz. :-)
Gábor
Dzięki. Ta metoda zawsze była komentowana bez ostrzeżeń. Mam CustomAdapter rozszerza ArrayAdapter <CustomListItem> z getCount (), getItem (...) i getView (...), używając „wzorca posiadacza”. Tak z ciekawości ...
dentex
Tak, możesz to zrobić, ponieważ ArrayAdapter rozszerza BaseAdapter i zapewnia już własną implementację.
Gábor
Z prostą tablicą wszystko w porządku. Ale rozważ inny przypadek, gdy chcesz na przykład wyświetlić elementy z bazy danych. Wtedy prawdopodobnie rozszerzysz BaseAdapter i możesz użyć tego długiego identyfikatora do przechowywania klucza bazy danych. Kiedy użytkownik coś wybierze, otrzymasz bezpośrednio z powrotem klucz wybranego rekordu za pośrednictwem argumentu id . Możesz na przykład od razu załadować go z bazy danych. Jedynym problemem jest to, że trzeba używać klawiszy numerycznych, bo Android zdecydował się na długi zamiast na coś szerszego.
Gábor
6

Plik getItemIdMetoda jest w dużej mierze przeznaczony do pracy z kursory, które są wspierane przez bazami danych SQLite. Zwróci pole id kursora bazowego dla elementu na pozycji 1.

W twoim przypadku nie ma identyfikatora dla elementu na pozycji 1: zakładam, że implementacja ArrayAdapter po prostu zwraca -1 lub 0.

EDYCJA: właściwie zwraca tylko pozycję: w tym przypadku 1.

Femi
źródło
2
Nie, to wraca -1. Oto realizacjaassert false : "TODO"; return -1;
rds
5
Począwszy od Androida 4.1.1, zwraca pozycję: grepcode.com/file/repository.grepcode.com/java/ext/…
emmby
4

Chciałbym wspomnieć, że po wdrożeniu getItemi getItemIdmożesz użyć ListView.getItemAtPosition i ListView.getItemIdAtPosition, aby uzyskać bezpośredni dostęp do danych, zamiast przechodzić przez adapter. Może to być szczególnie przydatne podczas implementowania nasłuchiwania onClick.

leo9r
źródło
3
Jest to rzeczywiście bardzo przydatne, jeśli masz nagłówek w widoku listy, a pozycje przekazane do modułu obsługi kliknięć różnią się o jeden
entropia,
4

Jeśli zaimplementujesz getItemIdpoprawnie, może to być bardzo przydatne.

Przykład:

Masz listę albumów:

class Album{
     String coverUrl;
     String title;
}

I wdrażasz w getItemIdten sposób:

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

Teraz twój identyfikator pozycji zależy od wartości pól coverUrl i title, a jeśli zmienisz to i wywołasz notifyDataSetChanged()adapter, adapter wywoła metodę getItemId () każdego elementu i zaktualizuje tylko te elementy, których id zmienił się.

Jest to bardzo przydatne, jeśli wykonujesz jakieś „ciężkie” operacje w swoim getView().

BTW: jeśli chcesz, żeby to zadziałało, musisz upewnić się, że twoja hasStableIds()metoda zwraca false;

Danylo Volokh
źródło
To cenna obserwacja. Czy możesz podać jakieś dane na poparcie tego mechanizmu selektywnej aktualizacji?
Jaime Agudo
Dlaczego powinien hasStableIds()zwrócić fałsz? Wydaje mi się, że hashcode obliczony z tego samego ciągu zwracałby za każdym razem tę samą wartość, która jest stabilnym identyfikatorem zgodnie z dokumentacją .
Big McLargeHuge
weź
2

getItemlub getItemIdjest kilka metod przeznaczonych głównie do załączania danych z pozycjami na liście. W przypadku getItem, możesz przekazać dowolny obiekt, który zostanie dołączony do pozycji na liście. Zwykle ludzie wracają null. getItemIdto dowolna unikalna longwartość, którą można dołączyć do tego samego elementu na liście. Ludzie zazwyczaj zwracają pozycję na liście.

Jakie jest zastosowanie. Ponieważ te wartości są powiązane z elementem na liście, możesz je wyodrębnić, gdy użytkownik kliknie element. Te wartości są dostępne za pomocą AdapterViewmetod.

// 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);
    }
});
Uday Hiwarale
źródło