ListView'ın geri dönüşüm mekanizması nasıl çalışır?


148

Bu yüzden daha önce yaşadığım bir problemim var ve doğal olarak burada yardım istedim . Luksprog'un cevabı harikaydı çünkü ListView ve GridView'ün geri dönüşüm Görünümleri ile kendisini nasıl optimize ettiği hakkında hiçbir fikrim yoktu. Bu yüzden onun tavsiyesiyle GridView'uma Görünümleri nasıl eklediğimi değiştirebildim. Sorun şu ki, mantıklı olmayan bir şeyim var. Bu getViewbenim BaseAdapter:


public View getView(int position, View convertView, ViewGroup parent) {
        if(convertView == null) {
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            convertView = inflater.inflate(R.layout.day_view_item, parent, false);
        }
        Log.d("DayViewActivity", "Position is: "+position);
        ((TextView)convertView.findViewById(R.id.day_hour_side)).setText(array[position]);
        LinearLayout layout = (LinearLayout)convertView.findViewById(R.id.day_event_layout);

        //layout.addView(new EventFrame(parent.getContext()));

        TextView create = new TextView(DayViewActivity.this);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 62, getResources().getDisplayMetrics()), 1.0f);
        params.topMargin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
        params.bottomMargin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
        create.setLayoutParams(params);
        create.setBackgroundColor(Color.BLUE);
        create.setText("Test"); 
        //the following is my original LinearLayout.LayoutParams for correctly setting the TextView Height
        //new LinearLayout.LayoutParams(0, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60, getResources().getDisplayMetrics()), 1.0f)   
        if(position == 0) {
            Log.d("DayViewActivity", "This should only be running when position is 0. The position is: "+position);
            layout.addView(create);
        }

        return convertView;
    }

}

Sorun şu ki, kaydırdığımda, bu oluyor ve konum 0'da değil ... Konum 6 ve konum 8'e benziyor, artı ikisini konum 8'e koyuyor. Şimdi hala ListView ve GridView'u kullanmayı öğrenmeye çalışıyorum, öyle yapıyorum bunun neden olduğunu anlamadım. Bu soruyu yapmamın ana nedenlerinden biri, ListView ve GridView'un geri dönüşüm Görünümü veya bu makalenin anlattığı yol , ScrapView mekanizması hakkında muhtemelen bilmeyenlere yardım etmektir.

görüntü açıklamasını buraya girin

Daha Sonra Düzenle

Google IO konuşmasına bağlantı eklemek, temelde ListView'ün nasıl çalıştığını anlamak için ihtiyacınız olan tek şey. Bağlantı, yorumların üzerine çıktı. Yani user3427079 bu bağlantıyı güncelleyecek kadar güzeldi. İşte kolay erişim için.


Haha, bu bağlantı için teşekkürler. Şimdi izlemeye
Andy

Önceki sorudaki kod örneğini tam olarak uygulamadınız. Buradaki fikir, diğer satırlar için yaptığınız değişiklikleri geri almak için her zaman bir kod parçasına ihtiyacınız olmasıdır (sizin durumunuzda konumunuz 0).
kullanıcı

Bunu anlıyorum @Luksprog Ama bu, View'u neden diğer pozisyonlara da koyduğunu açıklıyor mu? Herhangi bir şey varsa, yalnızca 0 konumunun yinelenen Görünümlere sahip olmasını bekliyordum. Idk, ListView'ün bu şeyleri nasıl bağladığını anlamakta hala sorun yaşıyor: /
Andy

1
Geri dönüşüm, ekrandan yeni kaybolan satır görünümünün (örneğin, bir satır aşağı kaydırıldıktan sonra 0 konumu), ListViewyeni bir satırın gösterilmesi gerektiğinde (aşağı / yukarı kaydırmaya devam etmek gibi) daha sonra kullanılabileceği anlamına gelir . Sorun şu ki, ortadan kaybolan ve ileride ihtiyaç duyulan pozisyonlarda kullanılacak görüş TextViewzaten ona eklendi, sorun bu. Bunu çözmek için getView, getViewyöntem dışında herhangi bir konum için çağrılmışsa , onu yöntemde kaldırmanız gerekir 0.
kullanıcı

2
En üstteki gönderinin bağlantısı kesildi, sanırım bu mu? youtube.com/watch?v=N6YdwzAvwOA
G_V

Yanıtlar:


334

Başlangıçta, listview geri dönüşümünün ve convertview kullanım mekanizmasının da farkında değildim, ancak bütün gün süren bir araştırmadan sonra, android.amberfog'dan bir resme atıfta bulunarak liste görünümünün mekanizmalarını hemen hemen anlıyorum. görüntü açıklamasını buraya girin

Liste görünümünüz bir bağdaştırıcı tarafından her doldurulduğunda, temelde liste görünümünün ekranda gösterebileceği Satırların sayısını gösterir ve listede gezinseniz bile satır sayısı artmaz. Listview'un daha verimli ve hızlı çalışması için android'in kullandığı hile budur. Şimdi, görüntüye atıfta bulunan liste görünümünün iç öyküsü, gördüğünüz gibi, başlangıçta liste görünümünde 7 görünür öğe vardır, ardından, öğe 1 artık görünmeyene kadar yukarı kaydırırsanız, getView () bu görünümü (yani öğe1) geri dönüşümcü ve kullanabilirsiniz

System.out.println("getview:"+position+" "+convertView);

senin içinde

public View getView(final int position, View convertView, ViewGroup parent)
{
    System.out.println("getview:"+position+" "+convertView);
    ViewHolder holder;
    View row=convertView;
    if(row==null)
    {
        LayoutInflater inflater=((Activity)context).getLayoutInflater();
        row=inflater.inflate(layoutResourceId, parent,false);
        
        holder=new PakistaniDrama();
        holder.tvDramaName=(TextView)row.findViewById(R.id.dramaName);
        holder.cbCheck=(CheckBox)row.findViewById(R.id.checkBox);
        
        row.setTag(holder);
        
    }
    else
    {
        holder=(PakistaniDrama)row.getTag();
    }
            holder.tvDramaName.setText(dramaList.get(position).getDramaName());
    holder.cbCheck.setChecked(checks.get(position));
            return row;
    }

Logcat'inizde, başlangıçta tüm görünür satırlar için convertview'un boş olduğunu fark edeceksiniz, çünkü başlangıçta geri dönüşüm cihazında hiçbir görünüm (yani öğeler) yoktu, bu nedenle getView () cihazınız görünen öğelerin her biri için yeni bir görünüm oluşturur, ancak yukarı kaydırdığınızda ve öğe 1 ekrandan çıktığında , mevcut durumuyla Geri Dönüştürücüye gönderilecektir (örneğin TextView 'metni' veya benim durumunda, onay kutusu işaretliyse, görünümle ilişkilendirilir ve geri dönüşüm cihazında saklanır).

Şimdi yukarı / aşağı kaydırdığınızda, liste görünümünüz yeni bir görünüm oluşturmayacak, geri dönüştürücünüzdeki görünümü kullanacaktır. Senin içinde LogCat size 'convertView' boş olmadığını fark edecektir, yeni madde 8 yani convertview kullanılarak çizilecektir çünkü onun, temelde onun yerine geri dönüşüm ve şişer öğe 8'den madde 1 görünümü alır ve gözlemleyebilirsiniz benim kodumda. Bir onay kutunuz varsa ve 0 konumunda kontrol ederseniz (diyelim ki öğe1'in bir onay kutusu vardı ve onu işaretlediniz), bu nedenle aşağı kaydırdığınızda öğe 8'in zaten işaretli olduğunu göreceksiniz, bu nedenle listview aynı görünümü kullanıyor, performans optimizasyonu nedeniyle sizin için yeni bir şey yaratmamak.

Önemli şeyler

1 . Set Hiç layout_heightve layout_widthsizin liste görünümü arasında wrap_contentolduğu gibi getView()liste görünümünde çekilecek görünümleri yüksekliğini ölçmek için bazı çocuğu almak için adaptör zorlar ve convertview hatta listeyi dönen gibi bazı beklenmeyen davranışlara neden olabilir scrolled.always kullanmak değildir match_parentveya sabit en boy.

2 . Eğer liste görünümü ve soru kudretini sonra biraz Düzen veya görünümünü kullanmak istiyorsanız ben ayarlarsanız aklınıza geldi layout_heightüzere fill_parenta içinde senin listview koymak onun daha iyi bu yüzden, ekran aşağı gider görünmez Liste görünümünde sonra görünüm Örneğin Doğrusal Düzen ve bu düzenin yüksekliğini ve genişliğini gereksiniminize göre ayarlayın ve liste görünümünüzün yükseklik ve genişlik özniteliğini düzeninize göre yapın (örneğin, düzen genişliğiniz 320 ve yükseklik 280 ise) sonra liste görünümünüz aynı yükseklik ve genişliğe sahip olmalıdır. Bu, getView () 'a işlenecek görünümlerin tam yüksekliğini ve genişliğini söyleyecektir ve getView () bazı rastgele satırları tekrar tekrar çağırmayacaktır ve kaydırma işlemi gerçekleşmeden önce dönüştürme görünümüne dönmek gibi diğer sorunlar, test ettim Listview benim için lineaLayout içinde değilse, aynı zamanda görünüm çağrısını tekrarlamak ve görünümü farklı dönüştürmek gibi sorunlar da yaşıyordu, Listview'i LinearLayout'a koymak benim için sihir gibi çalıştı. (nedenini bilmiyordum)

01-01 14:49:36.606: I/System.out(13871): getview 0 null
01-01 14:49:36.636: I/System.out(13871): getview 0 android.widget.RelativeLayout@406082c0
01-01 14:49:36.636: I/System.out(13871): getview 1 android.widget.RelativeLayout@406082c0
01-01 14:49:36.646: I/System.out(13871): getview 2 android.widget.RelativeLayout@406082c0
01-01 14:49:36.646: I/System.out(13871): getview 3 android.widget.RelativeLayout@406082c0
01-01 14:49:36.656: I/System.out(13871): getview 4 android.widget.RelativeLayout@406082c0
01-01 14:49:36.666: I/System.out(13871): getview 5 android.widget.RelativeLayout@406082c0
01-01 14:49:36.666: I/System.out(13871): getview 0 android.widget.RelativeLayout@406082c0
01-01 14:49:36.696: I/System.out(13871): getview 0 android.widget.RelativeLayout@406082c0
01-01 14:49:36.706: I/System.out(13871): getview 1 null
01-01 14:49:36.736: I/System.out(13871): getview 2 null
01-01 14:49:36.756: I/System.out(13871): getview 3 null
01-01 14:49:36.776: I/System.out(13871): getview 4 null

Ama şimdi çözüldü, biliyorum, açıklamada o kadar iyi değilim ama tüm günümü anlamaya ayırdığım için benim gibi diğer yeni başlayanların deneyimlerimden yardım alabileceğini düşündüm ve umarım şimdi sizler biraz anlayış kazanırsınız arasında ListView gerçekten dağınık ve gibi, nasıl çalıştığını çerçevesi zor bu yüzden yeni başlayanlar bunu anlamak çok fazla sorun buldum


36
"Açıklamada o kadar iyi olmadığımı biliyorum" >>> Bu cevabın +37 oyu bana açıklamada mükemmel bir iş çıkardığını söylüyor. Lütfen bilginizi paylaşmaya devam edin! ;)
2Dee

1
Harika cevap raja ji benden +1 .. :)
Ehsan Sajjad

2
Görüntü için teşekkürler. Android'e başladığımda ListView ile bir çok sorun yaşadıktan sonra, onunla bu kadar uğraştıktan sonra geri dönüşüm prensibini zaten biliyordum. Yine de bu resmi ve cümleyi çekti: if you had a checkbox and if you check it at position 0(let say item1 has also a checkbox and you checked it) so when you scroll down you will see item 8 checkbox is already checked,this is why listview is re using the same view not creating a new for you due to performance optimization.benim hatamı fark etmem için. Android ListView geri dönüşümü hakkında karşılaştığım en iyi gönderi!
Kevin Cruijssen

1
@MuhammadBabar Evet, Soru gönderdim: stackoverflow.com/q/30122027/1318946
Pratik Butani

1
@MuhammadBabar harika açıklama adamım! Zaman kazandırır. Sadece bilmek istiyorum RecyclerView, aynı mekanizma üzerinde de çalışıyor mu? Sorum ise stackoverflow.com/questions/47897770/... i görev imkansız sessiz biliyoruz listView. İle denemeli miyim recyclerView?
Shambhu

8

Tutucu modelinde, Tutucu nesnenizde konumu ayarlarsanız, her seferinde bunu ayarlamanız gerekir, örneğin:

@Override
public final View getView(int position, View view, ViewGroup parent) {
    Holder holder = null;
    if (view == null) {
        LayoutInflater inflater = (LayoutInflater) App.getContext()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = inflater.inflate(getContainerView(), parent, false);
        holder = getHolder(position, view, parent);
        holder.setTag(tag);
        view.setTag(holder);
    } else {
        holder = (Holder) view.getTag();
    }
    holder.position = position;
    draw(holder);
    return holder.getView();
}

bu soyut bir sınıftan bir örnektir, burada

getHolder(position, view, parent);

için tüm ayar işlemlerini yapar

ImageViews, TextViews, etc..

1
Bunca zamandır yaptığımı fark etmedim. parent.setTag(holder);doğru yol yerine,view.setTag(holder);
ArtiomLK

2

Tutucu modelini kullanarak istediğinizi elde edebilirsiniz:

Bu kalıbın açıklamasını burada bulabilirsiniz:

Liste görünümünün geri dönüşümü, ekranı aşağı kaydırdığınızda ve yukarıdaki liste görünümü öğeleri gizlendiğinde gerçekleşir. Yeni liste görünümü öğelerini göstermek için yeniden kullanılırlar.

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.