metode getView adapter tampilan kustom dipanggil beberapa kali, dan tanpa urutan yang koheren

162

Saya memiliki adaptor daftar khusus:

class ResultsListAdapter extends ArrayAdapter<RecordItem> {

dalam metode 'getView' yang ditimpa, saya mencetak untuk memeriksa posisi apa dan apakah itu convertView atau tidak:

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

Output dari ini (ketika daftar pertama kali ditampilkan, belum ada input pengguna)

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, meskipun saya tidak dapat menemukannya secara eksplisit, getView () hanya dipanggil untuk baris yang terlihat. Karena aplikasi saya dimulai dengan empat baris yang terlihat setidaknya nomor posisi yang dirangkai dari 0-3 masuk akal. Tetapi sisanya berantakan:

  • Mengapa getview dipanggil untuk setiap baris tiga kali?
  • Di mana konversi convertews ini berasal ketika saya belum menggulir?

Saya melakukan sedikit penelitian, dan tanpa mendapatkan jawaban yang baik, saya melihat ada orang yang mengaitkan masalah ini dengan masalah tata letak. Jadi dalam hal ini, inilah tata letak yang berisi daftar:

<?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>

dan tata letak setiap baris individual:

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

Terima kasih atas waktu Anda

edzillion
sumber

Jawaban:

271

Ini bukan masalah, sama sekali tidak ada jaminan pada urutan yang getView()akan dipanggil atau berapa kali. Dalam kasus khusus Anda, Anda melakukan hal terburuk dengan ListViewmemberikannya height=wrap_content. Ini memaksa ListViewuntuk mengukur beberapa anak keluar dari adaptor pada waktu tata letak, untuk mengetahui seberapa besar seharusnya. Ini adalah apa yang menyediakan ListViewdengan convertViewsAnda lihat dilewatkan ke getView()bahkan sebelum Anda gulir.

Guy Romain
sumber
10
Saya tidak menemukan ini alasan yang bagus. Tidak apa-apa jika Anda ingin dapat berubah, tetapi saat ini tidak menjawab mengapa melakukan perilaku ini?
cdpnet
45
@cdpnet Dia memang mengatakan mengapa itu melakukannya, Anda ListViewmemiliki ketinggian wrap_content, sehingga tidak yakin tentang tinggi badan karena itu memaparkan beberapa anak sebagai semacam tester untuk melihat apa yang cocok. Ubah Anda ListViewuntuk fill_parentkemudian memeriksa log Anda panggilan harus dikurangi secara dramatis.
Blundell
4
Perilaku antara era ListView 2.3 dan 4.x telah berubah secara signifikan. Yang perlu diperhatikan adalah, karena ListView dirancang, sel / list_items Anda harus murni dilihat dan harus dioptimalkan untuk menggambar dengan cepat. Menurut Google I / O talk di ListView, tempat Romain disajikan, getView mungkin dipanggil hanya untuk mengoptimalkan tampilan rendering dan membuang hasilnya. Sementara menurut saya ini tidak ramah pengembang seperti iOS UITableView, ini adalah bagaimana itu.
Cameron Lowell Palmer
4
Terima kasih banyak! Saya tidak mengerti mengapa getView () begitu sering dipanggil. Saya swithced wrap_content untuk fill_parent dan sekarang aplikasi saya cepat lagi :)
Julia Hexen
28
Seharusnya ada peringatan ketika mengatur ListViews ke layout_height = wrap_content karena menyebabkan begitu banyak masalah kinerja.
nathanielwolf
53

Cobalah dengan match_parentpada layout_heightproperti dari tampilan daftar. Itu akan mencegah getView()untuk dipanggil begitu sering.

Fred T
sumber
4
Perhatikan bahwa Fred T menentukan layout_height dari LIST VIEW ... bukan baris, yang saya coba berulang kali
mblackwell8
8
Catatan yang fill_parentharus diganti dengan match_parentuntuk API level 8 dan lebih tinggi.
Jason Axelson
Saya pikir metode getView () akan memanggil beberapa waktu, dengan mengatur lebar dan tinggi sebagai match_parent untuk ListView hanya menyelesaikan masalah kinerja.
Cuong Vo
45

Saya menyingkirkan masalah ini ketika saya mengubah layout_width dan layout_height menjadi match_parent (hanya mengubah layout_height tidak membantu).


Catatan berguna hati-hati jika Anda memiliki item bersarang. Anda harus mengubah yang "tertinggi" menjadi match_parent . Semoga ini bisa membantu seseorang.

Eugene Chumak
sumber
satu kata teman "luar biasa" tetapi tidak tahu mengapa wrap_content membuat masalah. Ini menyelesaikan masalah saya.
Android Killer
@AndroidKiller saat Anda gunakan wrap_content, maka ListViewtidak tahu berapa banyak item daftar yang ada untuk menjadi konten Daftar, itulah mengapa ListViewmencoba membuat sebanyak mungkin baris yang menurutnya cocok untuk ditampilkan, dan ketika Anda menggunakan fill_parentatau match_parent, ListViewberpikir, baiklah, tinggi saya adalah xdan saya perlu njumlah baris untuk ditampilkan.
Adil Soomro
Terima kasih banyak ! Dengan perilaku ini, gambar berubah secara acak karena beberapa panggilan ... Sekarang ini tidak apa-apa sejak awal.
Chostakovitch
7

Saya tidak dapat menjawab pertanyaan "Mengapa" Anda, tetapi saya pasti memiliki solusi untuk masalah " ListView items repeating " yang mengganggu (jika Anda memiliki item dalam koleksi Anda yang lebih dari ketinggian layar).

Seperti banyak orang di atas telah disebutkan, menjaga android: layout_height milik ListVew tag sebagai fill_parent .

Dan tentang fungsi getView (), solusinya adalah menggunakan kelas statis yang disebut ViewHolder . Lihatlah contoh ini . Berhasil melakukan tugas menambahkan semua item di Array atau ArrayCollection Anda.

Semoga ini bisa membantu teman !!

Salam, Siddhant

Siddhant
sumber
Berhati-hatilah dalam menggunakan pola ViewHolder di Android versi awal (pre ICS) karena dapat membawa Anda ke pengecualian MemoryLeak. jangan ragu untuk menggunakannya dalam versi ICS +.
Vahid Ghadiri
@Iddhant, terima kasih, saya menghabiskan satu hari untuk mencari tahu alasan pengulangan gambar di saya GridViewdan berubah android:layout_heightdan android:layout_widthtidak bekerja untuk saya. Tetapi dengan menggunakan ViewHoldergambar berulang tetap untuk saya, saya pergi melalui tutorial ini android-vogue.blogspot.com/2011/06/...
Nikolay Podolnyy
4

Pertanyaan: Mengapa panggilan Adapter getView () berkali-kali? Jawab: Saat Listview merender pada pengguliran adalah menyegarkan tampilan itu dengan tampilan berikutnya yang akan datang, yang adaptor perlu mendapatkan tampilan dengan memanggil getView ().

Pertanyaan: Mengapa panggilan lebih kecil jika lebar dan tinggi tampilan daftar diatur ke fill_parent? Jawab: Karena inflator memiliki ukuran tetap untuk area layar untuk daftar, ia menghitung satu kali untuk menampilkan tampilan ke layar.

Semoga ini akan menyelesaikan kueri Anda.

jitain sharma
sumber
Penjelasan yang bagus. Tetapi match_parent mungkin merupakan pilihan yang lebih baik.
Fattie
Ya @ JoBlow, disarankan untuk menggunakan match_parent daripada fill_parent dari API 2.4 / 3.0 dan seterusnya
jitain sharma
4

Saya mengalami masalah yang sama dengan dropdown di AutoCompleteTextView. Saya berjuang dengan masalah selama dua hari sampai saya tiba di sini dan Anda menunjukkan solusinya.

Jika saya menulis dropDownHeight = "match_parent" masalahnya sudah diperbaiki. Sekarang masalahnya terkait dengan UI (ketika Anda memiliki satu item dropdown terlalu besar) tetapi masalah beberapa panggilan (jauh lebih penting) telah diperbaiki.

Terima kasih!!

Pau Arlandis Martinez
sumber
2

"Mengapa getview dipanggil untuk setiap baris tiga kali?" Karena getView dipanggil ketika Anda menggulir pada tampilan daftar dan mengatakan lebih baik maka itu dipanggil ketika posisi tampilan daftar Anda diubah!

Ungureanu Liviu
sumber
ok, tapi tampilan belum berubah. ada empat tampilan baris di layar saat aktivitas dimulai, dan tanpa menggulir atau input pengguna apa pun, saya mendapatkan tiga panggilan getView untuk setiap baris ...
edzillion
Jawaban ini salah. Jawaban yang benar adalah bahwa menggunakan ** wrap_content ** menyebabkan sejumlah besar panggilan untuk getView.
Fattie
2

Saya memiliki masalah yang sama. Jika saya mengatur ketinggian ke fill_parent, maka saya mendapatkan "biasanya" 2 panggilan per baris. Tetapi, jika saya mengatur tinggi ListView saya ke nilai yang tepat, katakanlah menjadi 300dp, maka saya mendapatkan persis satu panggilan GetView per baris.

Jadi, menurut saya satu-satunya cara adalah pertama-tama menentukan ketinggian layar, kemudian secara terprogram mengatur tinggi listvilew ke nilai itu. Saya tidak suka itu. Saya harap ada cara yang lebih baik.

bobetko
sumber
1
Terima kasih untuk itu. Itu lucu - pertanyaan ini sudah tidak aktif selama berbulan-bulan sekarang hanya untuk memiliki beberapa komentar yang muncul selama beberapa minggu terakhir. Saya tidak lagi melakukan proyek ini tetapi karena saya punya waktu saya akan mencoba ini dan kemudian kembali ke sini untuk konfirmasi. Terima kasih lagi.
edzillion
sama di sini, saya mendapat dua panggilan per baris. Baris 0,1,2,3 dan kemudian 100 ms kemudian 0,1,2,3 lainnya - yang menyebalkan ketika mengumpulkan statistik tentang baris apa yang terlihat
Seseorang Di Suatu Tempat
2

Untuk Anda semua yang masih (Setelah mengatur to heightthe ) macet (seperti saya):ListViewmatch_parent

Anda juga harus mengatur heighttata letak induk ke match_parent.

Lihat contoh di bawah ini. The LinearLayoutadalah orang tua di sini:

<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>
B001 ᛦ
sumber
1

Ini mungkin datang terlambat tetapi jika Anda menggunakan layout_weightingat untuk selalu mengaturlayout_width="0dp"

Kuti Gbolahan
sumber
0

saya membuat solusi ini, mungkin bukan yang terbaik, tetapi apakah berhasil ...

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

lalu =

@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;
}

semoga membantu!

yago
sumber