2010-06-25 4 views
9

que estoy teniendo problemas con algún código BaseAdapter que me he adaptado de un libro. He estado usando variaciones de este código por todas partes en mi aplicación, pero recién me di cuenta de que al desplazarme por una larga lista, los elementos en el ListView se mezclan y no se muestran todos los elementos.BaseAdapter causando ListView para ir fuera de servicio cuando desplazado

Es muy difícil describir el comportamiento exacto, pero es fácil ver si se toma una lista ordenada de 50 artículos y empezar 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; 
    } 

} 

Respuesta

12

Solo está poniendo datos en los widgets TextView cuando se crean por primera vez. Es necesario 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()); 

a ser después el bloque if/else y antes del retorno del método, por lo que se actualizan los widgets de TextView si usted está reciclando la fila o crear una nueva.

+0

Oh, ya veo. Entonces, ¿ListView solo contiene como máximo el número de Vistas necesarias para llenar la pantalla? –

+0

@Mr. Ambiguo: más o menos. Puede almacenar en caché un par para poder reaccionar rápidamente a las solicitudes de desplazamiento. Sin embargo, en un 'ListView' con espacio de UI para 10 filas y un' Adaptador' de 1,000 filas, el número de 'Vistas' será mucho más cercano a 10 que 1,000. Probablemente como 12 o 14. Ese es el punto de reciclaje de filas con 'convertView', por lo que Android no tiene que crear (y más tarde GC) un lío completo de widgets de fila. – CommonsWare

5

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

El li.inflate funcionamiento (se necesita aquí para el análisis de la distribución de una fila a partir de XML y crear el objeto View caso) se envuelto por una declaración if (convertView == null) para la eficiencia, por lo que el inflado del mismo objeto no ocurrirá una y otra vez cada vez que aparece en la vista.

Sin embargo, las otras partes del método getView se utilizan para establecer otros parámetros y por lo tanto no deben incluirse dentro del si (convertView == null) {} else {...} comunicado.

En muchos implementación común de este método, algunos elementos de la etiqueta Textview, ImageView o ImageButton necesita ser poblada por los valores de la lista [posición], utilizando findViewById y después de eso .setText o .setImageBitmap operaciones . Estas operaciones deben venir después de ambos creando una vista desde cero por inflación y obteniendo una vista existente si no es nula (por ejemplo, en una actualización).

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

Cuestiones relacionadas