BaseAdapter Android sınıfındaki getItem ve getItemId yöntemlerinin amacı nedir?


155

Android SDK'daki yöntemlerin getItemve getItemIdsınıf Bağdaştırıcısının amacını merak ediyorum .

Açıklamasından, getItemaltta yatan verileri döndürmesi gerektiği anlaşılıyor . Yani, bir dizi ismim varsa ["cat","dog","red"]ve bunu kullanarak bir bağdaştırıcı aoluşturursam, a.getItem(1)"dog" döndürmeli, doğru mu? Ne a.getItemId(1)dönmeli?

Bu yöntemleri pratikte kullandıysanız, bir örnek verebilir misiniz?


16
+1 Mükemmel soru. Ben işaret etmek istiyorum getItemId()içinde ArrayAdapter()daima döndürür -1ileassert false : "TODO"; return -1;
RDS

Yanıtlar:


86

Bu yöntemleri listemin verilerine erişmek için daha temiz bir yaklaşım olarak görüyorum. Benim adaptör nesnesine doğrudan benim gibi bir şey üzerinden erişmek yerine myListData.get(position)sadece adaptörü gibi çağırabilirsiniz adapter.get(position).

Aynı şey geçerli getItemId. Listedeki bir nesnenin benzersiz kimliğine dayalı olarak bazı görevleri yürütmek istediğimde genellikle bu yöntemi kullanırdım. Bu özellikle bir veritabanı ile çalışırken kullanışlıdır. Döndürülen idveritabanındaki bir nesneye bir başvuru olabilir (daha sonra farklı işlemler gerçekleştirebilirim (güncelleme / silme / vb.).

Yani ham veri nesnesinden kimliğe erişmek yerine myListData.get(position).getId()kullanabilirsiniz adapter.getItemId(position).

Bu yöntemleri kullanmak için gerekli gibi hissettim bir örnek SeparatedListViewAdapter kullanarak bir projede oldu . Bu bağdaştırıcı, her biri farklı türde (tipik olarak) verileri temsil eden birden fazla farklı türde bağdaştırıcı içerebilir. Çağrılırken getItem(position), SeparatedListViewAdapterdöndürülen nesne, konumu hangi "bölüme" gönderdiğinize bağlı olarak farklı olabilir.

Örneğin, eğer Listenizdeki (meyve ve şeker) 2 bölümleri vardı: Eğer kullandıysanız getItem(position)ve positionbir öğenin üzerine olması oldu meyve istemiş ise daha farklı bir nesneyi alacak bölümünde getItem(position)ile positionbir öğeye işaret eden şeker Bölüm. Daha sonra getItemId(position), ne tür verilerin getItem(position)geri döndüğünü temsil eden bir çeşit sabit kimlik değeri döndürebilir veya instanceofsahip olduğunuz nesneyi belirlemek için kullanabilirsiniz .

Bahsettiğim dışında, bu yöntemleri gerçekten kullanmam gerektiğini hiç hissetmedim


7
sql ile ilgili olmayan bağdaştırıcılar için getItemId'ın hala bir amacı var mı? eğer öyleyse, ne iade edilmelidir? durum?
android geliştirici

1
yöntemin amacı veya kullanımı temel olarak geliştiriciye bağlıdır ve veritabanına dayalı bir uygulamaya bağlı değildir. net / okunabilir / yeniden kullanılabilir kod oluşturmak için avantajınıza kullanın.
james

1
Evet sanırım. getView, getCount, getViewTypeCount, Vb düzgün listview UI göstermek için özel olarak kullanılırlar. diğer işlevler sadece bir öğeyi tıklattıktan sonra başka eylemler gerçekleştirme gibi diğer işlevlerin uygulanmasına yardımcı olur, ancak sık sık getItemiçeride kullanıyorumgetView
james

1
@NicolasZozol Elbette - uygulamak getItemId, sadece iade etmek 0Lveya nullhiçbir yerde kullanmamak güvenlidir . Bir UUID'nin longkimlik için bir değerden daha değerli olmasının açık bir nedeni görmüyorum . Bağlantısı kesilmiş mod? Bu da ne?
james

1
@binnyb: Nicolas, UUID'lerle ağ bağlantısı olmasa bile geçerli benzersiz kimlikler (örneğin mobil cihazınızda) oluşturmanın mümkün olduğunu ifade ediyordu.
Levite

32

Görünüşe göre bu soru daha basit ve daha açık bir şekilde cevaplanabilir ... :-)

Basitçe söylemek gerekirse, Android longherhangi bir ListViewöğeye a eklemenize izin verir , bu kadar basit. Sistem kullanıcı seçimini size bildirdiğinde, neyin seçildiğini söylemek için üç tanımlayıcı değişken alırsınız :

  • görünümün kendisine bir referans,
  • listedeki sayısal konumu,
  • bunu longtek tek unsurlara bağladınız.

Bu üç durumdan hangisinin sizin durumunuz için en kolay olduğuna karar vermek size kalmıştır, ancak her üçünden de seçim yapabilirsiniz. Bunu long, öğeye otomatik olarak eklenen bir etiket olarak düşünün , sadece daha basit ve okunması daha kolay.

Genellikle yaptığı şeyle ilgili yanlış anlaşılma, basit bir sözleşmeden kaynaklanmaktadır. Tüm bağdaştırıcılar, getItemId()bu üçüncü kimliği gerçekten kullanmasalar bile , bir adaptör sağlamalıdır . Bu nedenle, konvansiyonel olarak, bu adaptörler (SDK'daki veya web'deki birçok örnek dahil) positiontek bir nedenden dolayı geri döner : her zaman benzersizdir. Yine de, bir adaptör getiri ise position, bu gerçek anlamı o tüm bu özelliği kullanmak istemiyor çünkü positionzaten bilinmektedir zaten.

Bu nedenle, uygun gördüğünüz başka bir değeri iade etmeniz gerekiyorsa, bunu yapmaktan çekinmeyin:

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

1
Bunun güzel açıklaması getItemId()... Bu yöntem özel bağdaştırıcınızda geçersiz kılındığında / geçersiz kılındığında ne olur?
Nisan'ta dentex

Temel sınıfta soyut olarak işaretlenmiş olmak zorundasınız. Tabii ki orijinal adaptörü geçersiz kılan bir şeyi geçersiz kılmadığınız sürece. Onu dışarıda bırakmaya çalışın ve Eclipse şikayet ederse, yapmanız gerekir. :-)
Gábor

Teşekkürler. Ben her zaman uyarı olmadan bu yöntemi yorum vardı. Bir CustomAdapter ArrayAdapter <CustomListItem> getCount (), getItem (...) ve getView (...), "tutucu desen" kullanarak genişletir var. Sadece meraktan ...
dentex

Evet, sen çünkü bunu yapabilir ArrayAdapter uzanır BaseAdapter zaten kendi uygulamasını sağlar.
Gábor

Ve basit bir dizi ile, sorun değil. Ancak, örneğin bir veritabanındaki öğeleri görüntülemek istediğinizde başka bir durumu düşünün. Daha sonra muhtemelen BaseAdapter genişleteceksiniz ve veritabanı anahtarını saklamak için bu uzun kimliği kullanabilirsiniz. Kullanıcı bir şey seçtiğinde, id argümanıyla seçilen kaydın anahtarını doğrudan geri alırsınız . Daha sonra, örneğin veritabanından hemen yükleyebilirsiniz. Sayısal anahtarlar kullanmanız gereken tek sorun, çünkü Android daha geniş bir şey yerine uzun bir süre karar verdi.
Gábor

6

getItemIdYöntem büyük ölçüde SQLite veritabanları ile desteklenmektedir imleçler ile çalışmak için tasarlanmıştır. Konum 1'deki öğe için temel imlecin kimlik alanını döndürür.

Sizin durumunuzda, konum 1'deki öğe için bir kimlik yok: ArrayAdapter uygulamasının sadece -1 veya 0 döndürdüğünü varsayıyorum.

EDIT: aslında, sadece pozisyonu döndürür: bu durumda 1.


2
Hayır geri döner -1. İşte uygulamaassert false : "TODO"; return -1;
rds

5
Android 4.1.1'den itibaren pozisyonu döndürür: grepcode.com/file/repository.grepcode.com/java/ext/…
emmby

4

Uyguladıktan sonra getItemve adaptör üzerinden gitmek yerine, doğrudan size veri erişmek için ListView.getItemAtPosition ve ListView.getItemIdAtPositiongetItemId kullanabilirsiniz bahsetmek istiyorum . Bu, bir onClick dinleyicisi uygulanırken özellikle yararlı olabilir.


3
Liste görünümünüzde bir başlığınız varsa ve tıklama işleyicisine iletilen konumlar bir kez kapalıysa bu gerçekten yararlıdır
entropi

4

Doğru uygularsanız getItemIdçok yararlı olabilir.

Misal :

Bir albüm listeniz var:

class Album{
     String coverUrl;
     String title;
}

Ve böyle uygularsınız getItemId:

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

Şimdi öğe kimliğiniz coverUrl ve başlık alanlarının değerlerine bağlıdır ve daha sonra değiştirir ve notifyDataSetChanged()bağdaştırıcınızı çağırırsanız, bağdaştırıcı her öğenin getItemId () yöntemini çağırır ve yalnızca kimliği değişmiş olan öğeleri güncelleştirir.

Eğer bazı "ağır" operasyonlar yapıyorsanız bu çok yararlıdır getView().

BTW: Bunun çalışmasını istiyorsanız, hasStableIds()yönteminizin false döndürdüğünden emin olmanız gerekir ;


Bu değerli bir gözlem, bu seçici güncelleme mekanizmasını desteklemek için bazı veriler sağlayabilir misiniz?
Jaime Agudo

Neden hasStableIds()yanlış döndürülmeli? Bana öyle geliyor ki, aynı dizeden hesaplanan hashcode her seferinde aynı değeri döndürür, bu da dokümanlara göre sabit bir kimliktir .
Büyük McLargeHuge

hashCode kullanmanın iki
Dizeye

2

getItemveya getItemIdesas olarak listedeki öğelerle birlikte veri eklemek için tasarlanmış birkaç yöntemdir. Durumunda getItem, listedeki öğeye eklenecek herhangi bir nesneyi iletebilirsiniz. Normalde insanlar geri döner null. getItemId, longlistede aynı öğeyle ekleyebileceğiniz benzersiz bir değerdir. İnsanlar genellikle listedeki konumu döndürür.

Ne faydası var. Bu değerler listedeki öğeye bağlı olduğundan, kullanıcı öğeyi tıkladığında bunları ayıklayabilirsiniz. Bu değerlere AdapterViewyöntemlerle erişilebilir .

// 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);
    }
});
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.