пользовательский метод getView адаптера списка, вызываемый несколько раз и не в последовательном порядке


162

У меня есть собственный адаптер списка:

class ResultsListAdapter extends ArrayAdapter<RecordItem> {

в переопределенном методе getView я делаю печать, чтобы проверить, какая позиция и является ли она convertView или нет:

    @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 вызывается для каждого ряда три раза?
  • Откуда приходят эти convertView, когда я еще не прокрутил?

Я сделал небольшой поиск и, не получив хорошего ответа, заметил, что люди связывают эту проблему с проблемами компоновки. Так что в случае, вот макет, который содержит список:

<?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помощью a height=wrap_content. Это заставляет ListViewотмерить несколько дочерних элементов адаптера во время разметки, чтобы понять, насколько большим он должен быть. Это то, что обеспечиваетListView что convertViewsвы видите переданным getView()еще до прокрутки.


10
Я не считаю это веской причиной. Это хорошо, если вы хотите иметь возможность измениться, но в настоящее время он не отвечает, почему он так поступает?
cdpnet

45
@cdpnet Он сказал , почему он делает это, ваши ListViewимеет высоту wrap_content, так что не уверена в его высоту поэтому лежит несколько детей, как своего рода тестер , чтобы увидеть , что будет вписываться в. Измените ваш , ListViewчтобы fill_parentзатем проверить журналы звонки должны быть резко сокращены.
Бланделл

4
Поведение между 2.3 и 4.x эрой ListView значительно изменилось. Вывод заключается в том, что при разработке ListView ваши ячейки / list_items должны быть чистыми представлениями и должны быть оптимизированы для быстрого рисования. Согласно докладу Google I / O о ListView, где представлен Romain, getView может быть вызван просто для оптимизации рендеринга представления и отклонения результата. Хотя, на мой взгляд, это не так удобно для разработчиков, как iOS UITableView, но так оно и есть.
Кэмерон Лоуэлл Палмер

4
Спасибо вам большое! Я не понимаю, почему getView () вызывается так часто. Я переключил wrap_content на fill_parent, и теперь мое приложение снова работает быстро :)
Юлия Хексен,

28
При установке ListViews на layout_height = wrap_content должно быть предупреждение, поскольку это вызывает очень много проблем с производительностью.
Натаниэльвольф

54

Попробуйте с match_parentпомощью layout_heightсвойства списка. Это помешает getView()так часто звонить.


4
Обратите внимание, что Фред Т задает layout_height LIST VIEW ... не строку, что я пытался много раз
mblackwell8

8
Обратите внимание, что fill_parentследует заменить match_parentна API уровня 8 и выше.
Джейсон Аксельсон

Я думаю, что метод getView () будет вызываться несколько раз, устанавливая ширину и высоту, так как match_parent для ListView только решает проблему производительности.
Куонг Во

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

Я не могу ответить на ваш вопрос «почему», но у меня определенно есть решение проблемы раздражающих элементов ListView, повторяющихся » (если в вашей коллекции есть элементы, размер которых превышает высоту экрана).

Как уже упоминали многие люди, оставьте свойство 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 ().

Ques: Почему он вызывает меньше, если ширина и высота списка просмотра установлена ​​в fill_parent? Ответ: Поскольку инфлятор имеет фиксированный размер области экрана для списка, он рассчитывает один раз для визуализации представлений на экране.

Надеюсь, это разрешит ваш запрос.


Отличное объяснение. Но match_parent может быть лучшим выбором.
Толстяк

Да @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.
Толстяк

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.