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

Solutions Collecting From Web of "BaseAdapter приводит к тому, что ListView выйдет из строя при прокрутке"

Вы только добавляете данные в виджеты 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 , перерабатываете ли строку или создаете новую.

Чтобы прояснить ответ CommonsWare, вот еще информация:

Операция li.inflate (необходимая для разбора компоновки строки из XML и создания соответствующего объекта View) завершается оператором if (convertView == null) для эффективности, поэтому инфляция одного и того же объекта не произойдет Снова и снова каждый раз, когда он появляется.

ОДНАКО, другие части метода getView используются для установки других параметров и поэтому НЕ должны быть включены в оператор if (convertView == null) {} … else {} .

Во многих распространенных реализациях этого метода некоторые элементы textView, ImageView или ImageButton должны быть заполнены значениями из списка [позиция], используя findViewById, а затем операции .setText или .setImageBitmap . Эти операции должны возникать после того, как вы создаете представление с нуля путем инфляции и получаете существующее представление, если оно не является нулевым (например, при обновлении).

Еще один хороший пример применения этого решения для ListView ArrayAdapter представлен в https://stackoverflow.com/a/3874639/978329