Apa maksud dari metode getItem dan getItemId di kelas Android BaseAdapter?

155

Saya ingin tahu tentang tujuan metode getItemdan getItemIddi kelas Adaptor di Android SDK.

Dari uraian, tampaknya getItemharus mengembalikan data yang mendasarinya. Jadi, jika saya memiliki array nama ["cat","dog","red"]dan saya membuat adaptor amenggunakan itu, maka a.getItem(1)harus mengembalikan "anjing", benar? Apa yang harus a.getItemId(1)dikembalikan?

Jika Anda menggunakan metode ini dalam praktiknya, dapatkah Anda memberikan contoh?

oneporter
sumber
16
+1 Pertanyaan bagus. Saya ingin menunjukkan bahwa getItemId()di ArrayAdapter()selalu mengembalikan -1denganassert false : "TODO"; return -1;
RDS

Jawaban:

86

Saya melihat metode ini sebagai pendekatan yang lebih bersih untuk mengakses data daftar saya. Alih-alih secara langsung mengakses objek adaptor saya melalui sesuatu seperti myListData.get(position)saya cukup memanggil adaptor seperti adapter.get(position).

Hal yang sama berlaku untuk getItemId. Biasanya saya akan menggunakan metode ini ketika saya ingin menjalankan beberapa tugas berdasarkan ID unik suatu objek dalam daftar. Ini sangat berguna saat bekerja dengan database. Yang dikembalikan idbisa menjadi referensi ke objek dalam database yang kemudian saya dapat melakukan operasi yang berbeda pada (pembaruan / hapus / dll).

Jadi, alih-alih mengakses ID dari objek data mentah seperti myListData.get(position).getId()yang dapat Anda gunakan adapter.getItemId(position).

Salah satu contoh di mana saya merasa perlu menggunakan metode ini adalah dalam proyek menggunakan SeparatedListViewAdapter . Adaptor ini dapat berisi berbagai jenis adaptor, masing-masing mewakili data dari jenis yang berbeda (biasanya). Saat menelepongetItem(position) padaSeparatedListViewAdapter , objek kembali mungkin berbeda tergantung pada "bagian" posisi adalah bahwa Anda kirimkan.

Sebagai contoh, jika Anda memiliki 2 bagian dalam daftar Anda (buah dan permen): Jika Anda menggunakan getItem(position)dan positionkebetulan berada pada item di bagian buah , Anda akan menerima objek yang berbeda daripada jika Anda diminta getItem(position)dengan positionmenunjuk ke item dalam permen. bagian. Anda kemudian dapat mengembalikan semacam nilai ID konstan getItemId(position)yang mewakili jenis data apa getItem(position)yang dikembalikan, atau gunakan instanceofuntuk menentukan objek apa yang Anda miliki.

Selain apa yang saya sebutkan, saya tidak pernah merasa benar-benar perlu menggunakan metode ini

james
sumber
7
untuk adaptor yang tidak terkait sql, apakah getItemId masih memiliki tujuan? jika demikian, apa yang harus dikembalikan? posisi?
pengembang android
1
tujuan atau penggunaan metode ini sebagian besar tergantung pada pengembang dan tidak terikat dengan aplikasi berbasis database. gunakan untuk keuntungan Anda untuk membuat kode yang jelas / dapat dibaca / dapat digunakan kembali.
james
1
Ya saya kira. getView, getCount, getViewTypeCount, Dll digunakan khusus untuk benar menampilkan UI ListView Anda. fungsi-fungsi lain hanya membantu membuat mengimplementasikan fungsi-fungsi lain seperti melakukan tindakan lebih lanjut setelah mengklik suatu item, dll. walaupun saya sering menggunakan getIteminsidegetView
james
1
@NicolasZozol Tentu- aman untuk tidak diimplementasikan getItemId, kembali saja 0Latau nulljangan gunakan di mana saja. Saya tidak melihat alasan yang jelas mengapa UUID akan lebih berharga dari sekadar longnilai ID. Mode terputus? Apa itu?
james
1
@binnyb: Nicolas bermaksud bahwa dengan UUID, masih dimungkinkan untuk membuat ID unik yang valid (mis. di perangkat seluler Anda), bahkan tanpa memiliki koneksi jaringan.
Levite
32

Yah, sepertinya pertanyaan ini bisa dijawab dengan cara yang lebih sederhana dan langsung ... :-)

Sederhananya, Android memungkinkan Anda untuk melampirkan item longapa pun ListView, sesederhana itu. Ketika sistem memberi tahu Anda tentang pilihan pengguna, Anda menerima tiga variabel pengenal untuk memberi tahu Anda apa yang dipilih:

  • referensi ke tampilan itu sendiri,
  • posisi numeriknya dalam daftar,
  • ini longAnda lampirkan pada elemen individual.

Terserah Anda untuk memutuskan mana dari ketiganya yang paling mudah untuk Anda tangani dalam kasus khusus Anda, tetapi Anda memiliki ketiganya untuk dipilih setiap saat. Anggap ini longsebagai tag yang secara otomatis dilampirkan pada item, hanya saja itu lebih sederhana dan lebih mudah dibaca.

Kesalahpahaman tentang apa yang biasanya terjadi berasal dari konvensi sederhana. Semua adaptor harus memberikan getItemId()bahkan jika mereka tidak benar-benar menggunakan identifikasi ketiga ini. Jadi, berdasarkan konvensi, adaptor tersebut (termasuk banyak sampel dalam SDK atau seluruh web) kembali positiondengan satu alasan: selalu unik. Namun, jika adaptor kembali position, ini benar-benar berarti ia tidak ingin menggunakan fitur ini sama sekali, karena positionsudah diketahui.

Jadi, jika Anda perlu mengembalikan nilai lain yang Anda inginkan, jangan ragu untuk melakukannya:

@Override
public long getItemId(int position) {
  return data.get(position).Id;
}
Gábor
sumber
1
Penjelasan yang bagus untuk ini getItemId()... Apa yang terjadi ketika / jika metode ini tidak diganti dalam adaptor khusus Anda?
dentex
Ditandai abstrak di kelas dasar, Anda harus. Kecuali Anda mengganti sesuatu yang menimpa adaptor asli, tentu saja. Cobalah untuk tidak melakukannya, dan jika Eclipse mengeluh maka Anda harus melakukannya. :-)
Gábor
Terima kasih. Saya selalu mengomentari metode ini tanpa peringatan. Saya memiliki CustomAdapter meluas ArrayAdapter <CustomListItem> dengan getCount (), getItem (...) dan getView (...), menggunakan "pola pemegang". Hanya ingin tahu ...
dentex
Yap, Anda bisa melakukannya karena ArrayAdapter memperluas BaseAdapter dan sudah menyediakan implementasinya sendiri.
Gábor
Dan dengan array sederhana, tidak apa-apa. Tapi pertimbangkan saja kasus lain, ketika Anda ingin menampilkan item dari database, misalnya. Anda kemudian mungkin akan memperpanjang BaseAdapter dan Anda dapat menggunakan ID panjang ini untuk menyimpan kunci basis data. Ketika pengguna memilih sesuatu, Anda akan langsung mendapatkan kembali kunci catatan yang dipilih melalui argumen id . Anda kemudian dapat memuatnya dari database segera, misalnya. Satu-satunya masalah adalah Anda harus menggunakan tombol angka karena Android memutuskan lama bukan sesuatu yang lebih luas.
Gábor
6

The getItemIdMetode sebagian besar dirancang untuk bekerja dengan Cursors yang didukung oleh database SQLite. Ini akan mengembalikan bidang id kursor yang mendasari untuk item di posisi 1.

Dalam kasus Anda, tidak ada id untuk item di posisi 1: Saya mengasumsikan implementasi ArrayAdapter hanya mengembalikan -1 atau 0.

EDIT: sebenarnya, itu hanya mengembalikan posisi: dalam hal ini 1.

Femi
sumber
2
Tidak itu kembali -1. Inilah implementasinyaassert false : "TODO"; return -1;
rds
5
Pada Android 4.1.1, ia mengembalikan posisi: grepcode.com/file/repository.grepcode.com/java/ext/…
emmby
4

Saya ingin menyebutkan bahwa setelah menerapkan getItemdan getItemIdAnda dapat menggunakan ListView.getItemAtPosition dan ListView.getItemIdAtPosition untuk langsung mengakses data Anda, alih-alih melalui adaptor. Ini mungkin sangat berguna ketika menerapkan pendengar onClick.

leo9r
sumber
3
Ini memang sangat berguna jika Anda memiliki tajuk pada tampilan daftar Anda dan posisi yang diteruskan ke penangan klik dimatikan oleh satu orang
entropi
4

Jika Anda menerapkan getItemIddengan benar maka itu mungkin sangat berguna.

Contoh:

Anda memiliki daftar album:

class Album{
     String coverUrl;
     String title;
}

Dan Anda menerapkan getItemIdseperti ini:

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

Sekarang id item Anda tergantung pada nilai-nilai coverUrl dan bidang judul dan jika Anda mengubahnya lalu memanggil notifyDataSetChanged()adaptor Anda, maka adaptor akan memanggil metode getItemId () dari setiap elemen dan memperbarui hanya item thouse yang id telah berubah.

Ini sangat berguna jika Anda melakukan beberapa operasi "berat" di komputer Anda getView().

BTW: jika Anda ingin ini berfungsi, Anda perlu memastikan hasStableIds()metode Anda kembali salah;

Danylo Volokh
sumber
Ini adalah pengamatan yang berharga, dapatkah Anda memberikan beberapa data untuk mendukung mekanisme pembaruan selektif ini?
Jaime Agudo
Kenapa harus hasStableIds()kembali salah? Sepertinya saya bahwa kode hash yang dihitung dari string yang sama akan mengembalikan nilai yang sama setiap kali, yang merupakan ID stabil menurut dokumen .
Big McLargeHuge
pertimbangkan bahwa menggunakan kode hash dapat mengembalikan true ke dua String
htafoya
2

getItematau getItemIdbeberapa metode yang terutama dirancang untuk data yang dilampirkan dengan item dalam daftar. Dalam hal ini getItem, Anda dapat melewati objek apa pun yang akan dilampirkan ke item dalam daftar. Biasanya orang kembali null. getItemIdadalah longnilai unik apa pun yang dapat Anda lampirkan dengan item yang sama dalam daftar. Orang umumnya mengembalikan posisi dalam daftar.

Apa gunanya. Nah, karena nilai-nilai ini terikat pada item dalam daftar, Anda dapat mengekstraknya ketika pengguna mengklik item tersebut. Nilai-nilai ini dapat diakses melalui AdapterViewmetode.

// 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
sumber