BaseAdapter заставляет ListView выходить из строя при прокрутке
У меня проблемы с некоторым кодом BaseAdapter, который я адаптировал из книги. Я использовал вариации этого кода повсюду в своем приложении, но только что понятый при прокрутке длинного списка элементы в ListView перепутались, а не все элементы отображаются.
Очень сложно описать точное поведение, но легко увидеть, если вы возьмете отсортированный список из 50 элементов и начнете прокрутку вверх и вниз.
class ContactAdapter extends BaseAdapter {
ArrayList<Contact> mContacts;
public ContactAdapter(ArrayList<Contact> contacts) {
mContacts = contacts;
}
@Override
public int getCount() {
return mContacts.size();
}
@Override
public Object getItem(int position) {
return mContacts.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
if(convertView == null){
LayoutInflater li = getLayoutInflater();
view = li.inflate(R.layout.groups_item, null);
TextView label = (TextView)view.findViewById(R.id.groups_item_title);
label.setText(mContacts.get(position).getName());
label = (TextView)view.findViewById(R.id.groups_item_subtitle);
label.setText(mContacts.get(position).getNumber());
}
else
{
view = convertView;
}
return view;
}
}
Ответы
Ответ 1
Вы только помещаете данные в виджеты TextView
, когда они сначала создаются. Вам нужно переместить эти четыре строки:
TextView label = (TextView)view.findViewById(R.id.groups_item_title);
label.setText(mContacts.get(position).getName());
label = (TextView)view.findViewById(R.id.groups_item_subtitle);
label.setText(mContacts.get(position).getNumber());
после блока if
/else
и перед возвратом метода, поэтому вы обновляете виджеты TextView
, если вы перерабатываете строку или создаете новую.
Ответ 2
Чтобы подробнее разъяснить ответ CommonsWare, вот еще информация:
Операция li.inflate(необходимая для разбора компоновки строки из XML и создания соответствующего объекта View) завершается оператором if (convertView == null) для эффективности, поэтому инфляция одного и того же объекта не будет происходить снова и снова каждый раз, когда он появляется.
ОДНАКО, другие части метода getView используются для установки других параметров и поэтому НЕ должны быть включены в оператор if (convertView == null) {}... else {}.
Во многих распространенных реализациях этого метода некоторые элементы textView, ImageView или ImageButton должны заполняться значениями из списка [позиция], используя findViewById и после этого .setText или .setImageBitmap.
Эти операции должны выполняться после создания представления с нуля путем инфляции и получения существующего представления, если оно не является нулевым (например, при обновлении).
Еще один хороший пример, когда это решение применяется для ListView ArrayAdapter, отображается в fooobar.com/info/22031/...