RecyclerView.ViewHolder - getLayoutPosition vs getAdapterPosition


90

Yeni destek kitaplığı sürümünden (22.x) bu yana, sınıfın getPosition()yöntemi RecyclerView.ViewHolder, konuda bahsedilen yöntemlerin yerine kullanımdan kaldırılmıştır. Dokümanları okumaktan gerçekten farkı anlamıyorum. Birisi meslekten olmayanların terimlerindeki farkı açıklayabilir mi?

Aşağıdaki kullanım durumum var - Adaptörüme bir veriyorum Listve ayrıca her liste öğesi için fazladan bilgi ilişkilendirebilmek istiyorum. Ekstra konum eşlemem var ve haritalama, konumlarına fazladan para alabilmeleri ve onunla bir şeyler yapabilmeleri için sahipler için mevcut. Sahipte hangi yöntemi kullanmalıyım?

0 ve 1 endekslerindeki liste öğeleri yer değiştirildiğinde tutucu konumlarına ne olur? Yöntemler ne döndürür?

Yanıtlar:


116

Bu aldatıcı bir durum, maalesef belgeler yeterli değil.

Adaptör içeriği değiştiğinde (ve siz çağırdığınızda notify***()) RecyclerView yeni bir düzen ister. O andan itibaren, yerleşim sistemi yeni bir yerleşim planını hesaplamaya karar verene kadar (<16 ms), düzen henüz adaptör değişikliklerini yansıtmadığından yerleşim konumu ve bağdaştırıcı konumu eşleşmeyebilir.

Kullanım durumunuzda, verileriniz adaptör içeriğinizle ilgili olduğu için (ve verilerin adaptör değişiklikleri ile aynı anda değiştiğini varsayıyorum), kullanmalısınız adapterPosition.

notifyDataSetChanged()Her şeyi geçersiz kıldığı için arıyorsanız dikkatli olun , RecyclerView bir sonraki düzen hesaplanana kadar ViewHolder'ın adaptör pozisyonunu bilmez. Bu durumda ( ) getAdapterPosition()döndürür .RecyclerView#NO_POSITION-1

Eğer aradım Ama eğer söz sağlayan notifyItemInserted(0), getAdapterPosition()pozisyonda daha önce hangi ViewHolder ait 0dönen başlayacaktır 1hemen. Parçalı bildirim olayları gönderdiğiniz sürece, her zaman iyi durumdasınız (yeni düzen henüz hesaplanmasa bile bağdaştırıcı konumunu biliyoruz).

Başka bir örnek, kullanıcı tıklamasıyla ilgili bir şey yapıyorsanız, getAdapterPosition()geri dönüyorsa NO_POSITION, en iyisi o tıklamayı yok saymaktır çünkü kullanıcının neye tıkladığını bilmiyorsunuz (başka bir mekanizma, örneğin öğeyi aramak için kararlı kimlikleriniz yoksa).

Düzen Konumu İyi Olduğunda Düzenleyin

Diyelim ki LinearLayoutManager, şu anda tıklanan öğenin üzerindeki ViewHolder'ı kullanıyorsunuz ve ona erişmek istiyorsunuz. Bu durumda, yukarıdaki öğeyi almak için yerleşim konumunu kullanmalısınız.

mRecyclerView.findViewHolderForLayoutPosition(myViewHolder.getLayoutPosition() - 1)

Düzen konumunu kullanmak zorundasınız çünkü kullanıcının o anda ekranda gördüğü konumla eşleşiyor.


1
Biraz oynadım ve getAdapterPosition () yöntemi her zaman bende -1 döndürüyor. Ben hata ayıkladım ve nedeni yöntemdeki kodun (final ViewParent parent = itemView.getParent (); if (! (Parent instanceof RecyclerView)) {return -1;} her zaman if bloğuna, yani geri dönüşümcü görünümüne girmesidir. hücre görünümümün üst öğesi değil Nasıl olabilir? Tutucuyu oluşturmak için kodum: return MyViewHolder (LayoutInflater.from (viewGroup.getContext ()). inflate (R.layout.test_list_item, viewGroup, false)); (Başka bir yorumda devam ediyor.)
wujek

İnflate (R.layout.test_list_item, viewGroup, true) çağırmak için kodu değiştirdiğimde; ('köke ekle' için doğruyu not edin), Android şunu atar: java.lang.IllegalStateException: Belirtilen alt öğenin zaten bir ebeveyni var. Önce çocuğun ebeveyninde removeView () 'u çağırmalısınız. Öyleyse, geri dönüşümcü görünümüne doğru şekilde eklenmiş bir görünümle bir görünüm tutucusu oluşturmanın doğru yolu nedir? Garip bir şekilde, getAdapterPosition (), ebeveyn boş olduğu için -1 döndürse bile, diğer her şey yolunda gider.
wujek

1
Düzen şişiricisindeki boole parametresi "addToParent" dir. Yanlış olmalıdır çünkü eklemek LayoutManager'ın sorumluluğundadır. Zaten konumu geçtiğiniz onBind içinde getAdapterPosition aradığınızı düşünüyorum. Teknik olarak, görünüm sahibi, onBind döndükten sonra bu konumu temsil eder. Btw, getAdapter konumunu, ayrılmış olsa bile geçerli bir pozisyon (mümkünse) döndürecek şekilde güncelledik, yakında yayınlanacaktır.
yiğit

Haklısın, onBind'da getAdapterPosition'ı arıyorum. Bunun yerine bu durumda ne yapmalıyım, bazı görüşlerin durumlarını etkileyen bazı bilgileri almak için pozisyona ihtiyacım var. Bu durumda getLayoutPosition çağırmak uygun mu?
wujek

5
OnBind yöntemine iletilen position parametresini kullanmalısınız.
yiğit

2


Fark (ler) in iddia etmek için getAdapterPosition(), getLayoutPosition()ve aynı zamanda position; aşağıdaki durumları fark ederiz:

1. yöntemdeki positionargüman onBindViewHolder():

Biz kullanabilirsiniz positiongörünümüne bağlamak verilere ve kullanımı tamamdır positionBunu yapmanın argümanı, ancak kullanmanın uygun olmadığı positionsap kullanıcı tıklamaları için argüman ve bunu kullanılırsa bir uyarı değil tedavi etmek" söyler göreceksiniz positionolarak düzeltildi ve holder.getAdapterPosition()bunun yerine kullan ".

2 getAdapterPosition().:

Bu yöntem her zaman güncellenmiş bağdaştırıcının holder. Bu, bir öğeye tıkladığınızda, adaptöre onun hakkında soru sormanız anlamına gelir position. böylece bu öğenin Adaptör mantığı açısından en son konumunu alacaksınız.

3 getLayoutPosition().:

Bazen, positiongüncellenen düzen açısından (kullanıcının şu anda görmekte olduğu son geçirilen düzen) bulmak gerekir, örneğin: Kullanıcı positiongörebileceği üçüncüyü sorarsa ve öğeler için swipe/ kullanırsanız dismissveya herhangi bir animasyon uygularsanız veya öğeler için süslemeler kullanmak getLayoutPosition()yerine kullanmak daha iyi olacaktır getAdapterPosition(), çünkü her zaman öğelerin en son geçirilen düzen açısından konumuyla uğraştığınızdan emin olacaksınız.


Bununla ilgili daha fazla bilgi için; buraya bakın . . .

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.