özel listview bağdaştırıcısı getView yöntemi birden çok kez çağrılıyor ve tutarlı bir sırada yok


162

Özel liste bağdaştırıcım var:

class ResultsListAdapter extends ArrayAdapter<RecordItem> {

geçersiz kılınan 'getView' yönteminde hangi pozisyon olduğunu ve bir convertView olup olmadığını kontrol etmek için bir baskı yapmak:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        System.out.println("getView " + position + " " + convertView);

Bunun çıktısı (liste ilk görüntülendiğinde henüz kullanıcı girişi yok)

04-11 16:24:05.860: INFO/System.out(681): getView 0 null  
04-11 16:24:29.020: INFO/System.out(681): getView 1 android.widget.RelativeLayout@43d415d8  
04-11 16:25:48.070: INFO/System.out(681): getView 2 android.widget.RelativeLayout@43d415d8  
04-11 16:25:49.110: INFO/System.out(681): getView 3 android.widget.RelativeLayout@43d415d8  
04-11 16:25:49.710: INFO/System.out(681): getView 0 android.widget.RelativeLayout@43d415d8  
04-11 16:25:50.251: INFO/System.out(681): getView 1 null  
04-11 16:26:01.300: INFO/System.out(681): getView 2 null  
04-11 16:26:02.020: INFO/System.out(681): getView 3 null  
04-11 16:28:28.091: INFO/System.out(681): getView 0 null  
04-11 16:37:46.180: INFO/System.out(681): getView 1 android.widget.RelativeLayout@43cff8f0  
04-11 16:37:47.091: INFO/System.out(681): getView 2 android.widget.RelativeLayout@43cff8f0  
04-11 16:37:47.730: INFO/System.out(681): getView 3 android.widget.RelativeLayout@43cff8f0  

AFAIK, açıkça ifade edilemese de getView () sadece görünür satırlar için çağrılır. Uygulamam dört görünür satırla başladığından, en azından 0-3 arasındaki bisiklet sayıları mantıklı. Ama gerisi bir karmaşa:

  • Neden her satır için getview üç kez çağrılır?
  • Henüz kaydırma yapmadığım zamanlarda bu convertView'lar nereden geliyor?

Biraz araştırma yaptım ve iyi bir cevap almadan, insanların bu sorunu düzen sorunları ile ilişkilendirdiğini fark ettim. Bu durumda, listeyi içeren düzen aşağıdadır:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="fill_parent"
    android:layout_width="fill_parent" 
    android:orientation="vertical" >

    <TextView android:id="@+id/pageDetails"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" />

    <ListView android:id="@+id/list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" 
        android:drawSelectorOnTop="false" />

</LinearLayout>

ve her bir satırın düzeni:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="108dp"    
android:padding="4dp">

<ImageView
    android:id="@+id/thumb"        
    android:layout_width="120dp"
    android:layout_height="fill_parent"        
    android:layout_alignParentTop="true"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_marginRight="8dp"        
    android:src="@drawable/loading" />

<TextView  
    android:id="@+id/price"
    android:layout_width="wrap_content"
    android:layout_height="18dp"         
    android:layout_toRightOf="@id/thumb"
    android:layout_alignParentBottom="true"       
    android:singleLine="true" />

<TextView  
    android:id="@+id/date"
    android:layout_width="wrap_content"
    android:layout_height="18dp"         
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true" 
    android:paddingRight="4dp"       
    android:singleLine="true" />

<TextView
    android:id="@+id/title"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textSize="17dp" 
    android:layout_toRightOf="@id/thumb"
    android:layout_alignParentRight="true"
    android:layout_alignParentTop="true"
    android:paddingRight="4dp"   
    android:layout_alignWithParentIfMissing="true"
    android:gravity="center" />

</RelativeLayout>

Zaman ayırdığın için teşekkürler

Yanıtlar:


271

Bu bir sorun değil, hangi sırayla getView()çağrılacağına veya kaç kez verileceğine dair hiçbir garanti yoktur . Sizin özel durumda, bir ile mümkün en kötü şeyi yapıyorlar ListViewbunu bir vererek height=wrap_content. Bu ListView, yerleşim sırasında birkaç çocuğu adaptörden ölçmeye ve ne kadar büyük olması gerektiğini bilmeye zorlar . Bu ne sağlayan ListViewile convertViewssize geçirilen görmek getView()kaydırma önce bile.


10
Bunun iyi bir nedeni bulamıyorum. Değiştirmek istiyorsanız sorun değil, ancak şu anda bu davranışı neden yaptığını yanıtlamıyor?
cdpnet

45
@cdpnet bunu neden yaptığımı O sizin, dedin ListViewbir yüksekliğe sahiptir wrap_contento 's yüksekliğinin emin değildir bu yüzden, bu nedenle sığmaktadır ne olduğunu görmek için test bir tür olarak bazı çocuklar bırakır. senin değiştirme ListViewiçin fill_parentdaha sonra günlükleri kontrol çağrılar önemli ölçüde azaltılmalıdır.
Blundell

4
2.3 ve 4.x dönemi ListView arasındaki davranış önemli ölçüde değişti. TakeView, ListView tasarlandığından, hücrelerinizin / list_items öğelerinizin saf görünümler olması ve hızlı bir şekilde çizim için optimize edilmeleri gerekir. Romain'in sunduğu ListView'deki Google I / O konuşmasına göre, getView yalnızca görünüm oluşturmayı optimize etmek ve sonucu atmak için çağrılabilir. Bence bu iOS UITableView kadar geliştirici dostu olmasa da, böyle.
Cameron Lowell Palmer

4
Çok teşekkür ederim! GetView () neden bu kadar sık ​​çağrıldığını anlamadım. Ben wrap_content doldurmak için swithced ve şimdi benim app tekrar hızlı :)
Julia Hexen

28
ListView'leri düzen_height = wrap_content olarak ayarlarken bir uyarı olmalı, çünkü çok fazla performans sorununa neden oluyor.
nathanielwolf

53

İle deneyin match_parentüzerinde layout_heightliste görünümündeki özelliği. Bu getView()kadar sık ​​çağrılmasını engelleyecektir .


4
Fred T, LIST GÖRÜNÜMÜNün layout_height değerini belirlediğine dikkat edin ... satır değil, tekrar tekrar denediğim şey
mblackwell8

8
Bunun API seviye 8 ve üstü için fill_parentdeğiştirilmesi gerektiğini unutmayın match_parent.
Jason Axelson

Ben getView () yöntemi ListView için match_parent olarak genişliği ve yüksekliği ayarlayarak birden çok kez çağıracağını düşünüyorum sadece performans sorunu çözmek.
Cuong Vo

45

Ben layout_width ve layout_height hem match_parent için değiştirdiğimde bu sorundan kurtuldum (sadece layout_height değiştirme yardımcı olmadı).


Yuvalanmış öğeleriniz varsa yararlı not dikkat edin. "En yüksek" olanı match_parent olarak değiştirmeniz gerekir . Umarım birine yardımcı olur.


bir kelime dostum "harika" ama neden wrap_content sorun yarattığını bilmiyorum. Bu benim sorunumu çözdü.
Android Killer

Kullandığınızda @AndroidKiller wrap_contentardından ListViewList içerik var olmaya ne kadar liste öğesi bilmiyorum nedeni bu ListViewo düşündüğü gibi çalışır sayıda satır olarak oluşturmak için ekrana uygundur ve kullandığınızda fill_parentveya match_parent, ListViewtamam, benim yükseklik düşünüyor olduğunu xve ihtiyacım ngöstermek için satır sayısını.
Adil Soomro

Çok teşekkür ederim ! Bu davranış ile görüntüler birden fazla çağrı nedeniyle rastgele değişiyordu ... Şimdi başından beri bu tamam.
Chostakovitch

7

"Neden" sorunuza cevap veremiyorum ama kesinlikle rahatsız edici " ListView öğeleri yinelenen " sorununa bir çözüm var (ekran koleksiyonundan daha fazla ur toplama öğeleri varsa).

Yukarıdaki birçok kişinin belirttiği gibi, ListVew etiketinin android: layout_height özelliğini fill_parent olarak tutun .

GetView () işlevi hakkında çözüm, ViewHolder adlı statik bir sınıf kullanmaktır . Check out Bu örnek. Başarılı bir şekilde ur Array veya ArrayCollection içindeki tüm öğeleri ekleme görevini yapar.

Umarım bu arkadaşlara yardımcı olur !!

Saygılarımızla, Siddhant


Sizi MemoryLeak istisnasına yol açabileceğinden, Android'in (ICS öncesi) erken sürümünde ViewHolder desenini kullanma konusunda dikkatli olun. ICS + sürümlerinde kullanmaktan çekinmeyin.
Vahid Ghadiri

@Siddhant teşekkürler yaşıyorum benim, yinelenen görüntüleri nedenle dışarı günde tto figürü geçirmek GridViewve değişen android:layout_heightve android:layout_widthbenim için çalışmalarını yapmaz. Ama ViewHolderbenim için sabit tekrarlanan görüntüler kullanarak bu öğretici üzerinden geçti android-vogue.blogspot.com/2011/06/…
Nikolay Podolnyy

4

Ques: Bağdaştırıcı neden getView () birçok kez çağırıyor? Cv: Listview kaydırma üzerinde oluşturduğu için, bir sonraki yaklaşan görünümlerle görünümünü yenilediğinden, adaptörün getView () öğesini çağırarak görüntülemeye ihtiyacı vardır.

Ques: Liste görünümü genişliği ve yüksekliği fill_parent olarak ayarlanmışsa neden daha az çağrı yapıyor? Cvp: Şişirme, liste için ekran alanı için sabit bir boyuta sahip olduğundan, görünümleri ekrana işlemek için bir kez hesaplar.

Sorgunuzu çözeceğini umuyoruz.


Harika bir açıklama. Ancak match_parent daha iyi bir seçim olabilir.
Fattie

@JoeBlow, API 2.4 / 3.0'dan itibaren fill_parent yerine match_parent kullanılması önerilir
jitain sharma

4

AutoCompleteTextView açılır liste ile aynı sorunu yaşıyordu. Buraya gelene ve bana çözümü gösterene kadar iki gün boyunca sorunla savaşıyordum.

DropDownHeight = "match_parent" yazarsam sorun giderilir. Şimdi sorun UI ile ilgilidir (bir öğeniz olduğunda açılır liste çok büyüktür) ancak birden fazla çağrı sorunu (çok daha önemli) düzeltildi.

Teşekkür ederim!!


2

"Neden her satır için getview üç kez çağrılıyor?" Çünkü liste görünümünde kaydırma yaptığınızda getView çağrılır ve daha iyi söylemek için listenizdeki bir görünümün konumu değiştiğinde çağrılır!


Tamam, ama görünüm değişmedi. etkinlik başladığında ekranda dört satır görünümü vardır ve herhangi bir kaydırma veya herhangi bir kullanıcı girişi olmadan ben her satır için üç getView çağrı olsun ...
edzillion

Bu cevap yanlış. Doğru cevap ** wrap_content ** kullanmanın çok sayıda çağrının getView'e neden olmasıdır.
Fattie

2

Aynı sorunu yaşıyorum. Fill_parent olarak ayarlanmış yüksekliğim varsa, satır başına "genellikle" 2 çağrı alırım. Ancak, ListView'imin yüksekliğini tam değere ayarlarsam, diyelim ki 300dp'ye, o sırada her satırda tam olarak bir GetView çağrısı alıyorum.

Bana öyle geliyor ki, tek yol önce ekranın yüksekliğini belirlemek, sonra listvilew yüksekliğini programlı olarak bu değere ayarlamaktır. Sevmiyorum. Umarım daha iyi bir yol vardır.


1
Bunun için teşekkürler. Komik - bu soru aylardır uykuda kaldı, son birkaç hafta içinde sadece birkaç yorum var. Artık bu projeyi yapmıyorum ama biraz zamanım olduğundan bunu deneyeceğim ve onaylamak için buraya döneceğim. Tekrar teşekkürler.
edzillion

burada aynı, her satırda iki çağrı alıyorum. Sıralar 0,1,2,3 ve daha sonra 100ms sonra başka bir 0,1,2,3 - hangi satırların göründüğü hakkında istatistik toplarken kıçta bir acı
Birisi Bir Yer

2

(Ayarladıktan sonra hala kim hepsi için heightbir ListViewetmek match_parent) (Ben gibi) sıkışmış gibidir:

heightÜst düzeni de ayarlamanız gerekir match_parent.

Aşağıdaki örneğe bakın. LinearLayoutBurada ebeveyn geçerli:

<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/something" />

        <ListView
            android:id="@+id/friendsList"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>

1

Bu belki geç geliyor ama kullandığınız takdirde layout_weighther zaman ayarlamayı unutmayınlayout_width="0dp"


0

Bu çözümü yaptım, belki de en iyisi değil, ama iş ...

//initialize control string
private String control_input = " ";

o zaman =

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    View gridview = convertView;

    // change input_array for the array you use
    if (!control_input.equals(input_array[position])) {
        control_input = input_array[position];

        //do your magic

    } 

    return gridview;
}

Umarım yardımcı olur!

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.