BaseAdapter que hace que ListView salga de orden cuando se desplaza

Tengo problemas con algún código de BaseAdapter que adapté de un libro. He estado utilizando variaciones de este código en todo el lugar de mi aplicación, pero sólo se dio cuenta cuando se desplaza una lista larga de los elementos en el ListView se mezclan y no todos los elementos se muestran.

Es muy difícil describir el comportamiento exacto, pero es fácil ver si se toma una lista ordenada de 50 elementos y empieza a desplazarse hacia arriba y hacia abajo.

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

Sólo se están poniendo datos en los widgets de TextView cuando se crean por primera vez. Necesitas mover estas cuatro líneas:

  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()); 

Para estar después del bloque if / else y antes del retorno del método, por lo que actualiza los widgets TextView si está reciclando la fila o creando una nueva.

Para aclarar más la respuesta de CommonsWare, aquí hay más información:

La operación li.inflate (necesaria aquí para analizar el diseño de una fila de XML y crear el objeto de vista apropiado) está envuelta por una instrucción if (convertView == null) para la eficiencia, por lo que no sucederá la inflación del mismo objeto Una y otra vez cada vez que aparece a la vista.

SIN EMBARGO, las otras partes del método de getView se utilizan para fijar otros parámetros y por lo tanto NO se deben incluir en la instrucción if (convertView == null) {} … else {} .

En muchas implementaciones comunes de este método, algunos elementos textView, ImageView o ImageButton necesitan ser poblados por valores de la lista [position], usando findViewById y después de las operaciones .setText o .setImageBitmap . Estas operaciones deben venir después de crear una vista desde cero por inflación y obtener una vista existente si no es nula (por ejemplo, en una actualización).

Otro buen ejemplo donde se aplica esta solución para un ListView ArrayAdapter aparece en https://stackoverflow.com/a/3874639/978329

  • Lazy cargando ViewPagers en un ScrollView
  • ¿Es posible tener siempre fastscroll habilitado en un listview?
  • ¿Añade nuevos elementos a la parte superior de la vista de lista en Android?
  • Android: ListView, Último elemento - Mostrar más
  • Cómo deshabilitar un elemento secundario en un listview (hacer su color gris y unclickable)
  • Cómo utilizar View Holder al tener filas diferentes en un ListView
  • ¿Cómo obtengo el ID de fila de la fila de un ListView, que contiene un elemento que se puede hacer clic?
  • ¿Cuál es la diferencia entre los dos tipos de implementación de la getView ()?
  • Cómo mantener la vista de lista para mostrar la última fila
  • Seleccionar todos los elementos de ListView
  • Android ListView Ir a la posición del cursor
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.