спеціальний адаптер перегляду списку метод getView викликається декілька разів, і не в узгодженому порядку


162

У мене є адаптер спеціального списку:

class ResultsListAdapter extends ArrayAdapter<RecordItem> {

у перекритому методі 'getView' я роблю друк, щоб перевірити, що таке положення і чи є це ConverView чи ні:

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

Вихід цього (коли вперше відображається список, ще немає вводу користувача)

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, хоча я не міг знайти його чітко зазначено, getView () викликається лише для видимих ​​рядків. Оскільки мій додаток починається з чотирьох видимих ​​рядків, принаймні номери позицій, що переходять із 0-3 має сенс Але решта - безлад:

  • Чому виклик getview для кожного ряду тричі?
  • Звідки беруться ці ConverView, коли я ще не прокручував?

Я трохи переглянув, і не отримавши гарної відповіді, я помітив, що люди пов'язують це питання з проблемами розмітки. Тож у випадку, ось макет із списком:

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

та макет кожного окремого рядка:

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

Спасибі за ваш час

Відповіді:


271

Це не проблема, немає абсолютно жодної гарантії того, в якому порядку getView()буде закликано, ні скільки разів. У вашому конкретному випадку ви робите найгірше, що можливо, з ListViewподанням цього height=wrap_content. Це змушує ListViewвідміряти декількох дітей, які виходять із адаптера під час розстановки, щоб знати, наскільки він повинен бути великим. Це те, що надається вам, ListViewпро який convertViewsви бачите, пройдене getView()ще до прокрутки.


10
Я не вважаю це вагомою причиною. Це добре, якщо ви хочете змінитись, але наразі це не відповідає, чому він робить таку поведінку?
cdpnet

45
@cdpnet Він сказав, чому це робив, у вас ListViewвисота wrap_content, тому він не впевнений, що це висота, тому він відкладає деяких дітей як своєрідний тестер, щоб побачити, що підійде. Змініть свій, ListViewщоб fill_parentпотім перевірити свої журнали. дзвінки повинні бути різко скорочені.
Blundell

4
Поведінка між епохами 2.3 та 4.x ListView суттєво змінилася. Здійснення забирає, як розроблено ListView, ваші клітинки / list_items повинні бути чистими переглядами, і їх потрібно оптимізувати для малювання швидко. Згідно з розмовами вводу-виводу Google в ListView, де представлений Ромен, getView може бути викликано просто для оптимізації візуалізації перегляду та відхилення результату. Хоча, на мою думку, це не настільки приємно для розробників, як iOS UITableView, це все так.
Камерон Лоуелл Палмер

4
Дуже дякую! Я не розумів, чому так часто називають getView (). Я змахнувся на wrap_content на fill_parent, і тепер моя програма знову швидка :)
Julia Hexen

28
Під час встановлення ListViews має бути попередження для layout_height = wrap_content, оскільки це викликає стільки проблем із продуктивністю.
nathanielwolf

53

Спробувати match_parentна layout_heightвластивості списку. Це заважатиме getView()називатися так часто.


4
Зауважте, що Ф. Т вказує layout_height СПИСОКУ СПИСОК ... а не рядок, який я намагався знову і знову
mblackwell8

8
Зауважте, що його fill_parentслід замінити match_parentна рівень API 8 і вище.
Джейсон Аксельсон

Я думаю, що метод getView () зателефонує декілька разів, встановивши ширину та висоту як відповідність для ListView лише вирішити проблему з продуктивністю.
Cuong Vo

45

Я позбувся цієї проблеми, коли змінив як layout_width, так і layout_height на match_parent (зміна лише layout_height не допомогло).


Корисна примітка слідкуйте, якщо ви вклали елементи. Ви повинні змінити "найвищий" на match_parent . Сподіваюся, це комусь допоможе.


одне слово приятель "дивовижно", але не знаю, чому wrap_content створює проблему. Це вирішило моє питання.
Android Killer

@AndroidKiller, коли ви використовуєте wrap_content, тоді ListViewне знаю, скільки є списку, щоб стати вмістом списку, ось чому ListViewнамагається створити стільки рядків, скільки він вважає придатними для відображення, і коли ви використовуєте fill_parentабо match_parent, думаєте ListView, добре, мій зріст є xі мені потрібно nпоказати кількість рядків.
Аділ Соомро

Дуже дякую ! З такою поведінкою зображення випадково змінювалися через багаторазові дзвінки ... Тепер це все нормально з початку.
Чостакович

7

Я не в змозі відповісти на ваше запитання "Чому", але у мене, безумовно, є рішення проблеми, що дратує " Повідомлення, які повторюються " (якщо у вас є елементи в колекції ур, які перевищують висоту екрану).

Як уже згадувало багато людей вище, зберігайте властивість android: layout_height тегу ListVew як fill_parent .

Щодо функції getView (), рішення полягає у використанні статичного класу під назвою ViewHolder . Перевірте це прикладом. Він успішно виконує завдання додавання всіх елементів в ур Array або ArrayCollection.

Сподіваюся, це допомагає друзям !!

З найкращими побажаннями, Сіддхант


Будьте обережні щодо використання шаблону ViewHolder у ранній версії Android (до ICS), оскільки це може призвести до виключення MemoryLeak. сміливо використовуйте його у версіях ICS +.
Вахід Ґадірі

@Siddhant дякую, що я витрачаю день, щоб з'ясувати причину повторення зображень у моїх GridViewі зміни, android:layout_heightі android:layout_widthне працює для мене. Але використовуючи ViewHolderфіксовані повторювані зображення для мене, я пройшов цей підручник android-vogue.blogspot.com/2011/06/…
Микола Подольний

4

Питання: Чому адаптер дзвонить getView () багато разів? Відповідь: Оскільки Listview рендерінгу прокрутки оновлює його перегляд з наступними майбутніми переглядами, для яких адаптеру потрібно отримати представлення, зателефонувавши getView ().

Питання: Чому дзвінки менші, якщо ширина та висота списку перегляду встановлені для заповнення_прозорого? Відповідь: Оскільки інфлятор має фіксований розмір області екрану для списку, він обчислює один раз для відображення подань на екран.

Сподіваємось, він вирішить ваш запит.


Чудове пояснення. Але кращий вибір може бути match_parent .
Fattie

Так @JoeBlow, рекомендується використовувати match_parent замість fill_parent від API 2.4 / 3.0 далі
jitain sharma

4

У мене була така ж проблема з випадаючим меню в AutoCompleteTextView. Я боровся з проблемою два дні, поки я не приїду сюди, і ви не покажете мені рішення.

Якщо я напишу dropDownHeight = "match_parent", проблема виправлена. Тепер проблема пов’язана з інтерфейсом користувача (коли у вас є один елемент, спадне місце занадто велике), але проблема кількох дзвінків (набагато важливіше) виправлена.

Дякую!!


2

"Чому виклик getview для кожного ряду тричі?" Тому що getView викликається при прокручуванні списку перегляду і краще сказати, що він називається, коли положення перегляду вашого списку змінено!


ОК, але погляд не змінився. на екрані є чотири перегляди рядків, коли активізація починається, і без прокрутки або будь-якого введення користувача я отримую три виклики getView для кожного рядка ...
edzillion

Ця відповідь неправильна. Правильна відповідь полягає в тому, що використання ** wrap_content ** викликає величезну кількість дзвінків до getView.
Fattie

2

У мене те саме питання. Якщо у мене встановлена ​​висота fill_parent, я отримую "зазвичай" 2 дзвінки в ряд. Але якщо я встановив висоту мого ListView на точне значення, скажімо, на 300dp, то я отримаю рівно один виклик GetView в ряд.

Отже, мені здається, що єдиний спосіб - це спочатку визначити висоту екрану, а потім програмно встановити висоту listvilew до цього значення. Мені це не подобається. Я сподіваюся, що є кращий шлях.


1
Дякую за це. Це смішно - це питання лежить у спокої вже місяцями, лише за те, що останні кілька тижнів з'явилися декілька коментарів. Я вже не займаюся цим проектом, але оскільки у мене є певний час, я спробую це спробувати, а потім повернусь сюди, щоб підтвердити. знову дякую.
edzillion

тут же я отримую два дзвінки в ряд. Рядки 0,1,2,3, а потім через 100 мс ще 0,1,2,3 - це біль у дупі під час збору статистичних даних про те, що бачать рядки
Хтось десь

2

Для всіх, хто досі (Після встановлення параметра height" ListViewдо"match_parent ) застрягли (як я):

Ви також повинні встановити heightбатьківський макет наmatch_parent .

Дивіться приклад нижче. Тут LinearLayoutє батько:

<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

Це може бути пізно, але якщо ви використовуєте layout_weightпам'ятати, щоб завжди встановлюватиlayout_width="0dp"


0

я прийняв це рішення, можливо, це не найкращий варіант, але це працює ...

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

тоді =

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

сподіваюся, що це допоможе!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.