2010-06-25 5 views
9

J'ai des problèmes avec le code BaseAdapter que j'ai adapté à partir d'un livre. J'ai utilisé des variantes de ce code partout dans mon application, mais seulement réalisé en faisant défiler une longue liste les éléments dans le ListView deviennent brouillés et tous les éléments ne sont pas affichés.BaseAdapter provoquant le désordre de ListView lors du défilement

Il est très difficile de décrire le comportement exact, mais il est facile de voir si vous prenez une liste triée de 50 éléments et commencez à défiler vers le haut et vers le bas.

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

} 

Répondre

12

Vous ne mettez que des données dans les widgets TextView lors de leur création. Vous devez déplacer ces quatre lignes:

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

être après le bloc if/else et avant le retour de la méthode, de sorte que vous mettez à jour les TextView widgets que vous recyclez la ligne ou de créer un nouveau.

+0

Oh, je vois. Ainsi, le ListView ne contient que le nombre de vues nécessaires pour remplir l'écran. –

+0

@Mr. Ambigueux: Plus ou moins. Il peut mettre en cache un couple pour pouvoir réagir rapidement aux demandes de défilement. Cependant, dans un 'ListView' avec un espace UI pour 10 lignes et un' Adapter' de 1000 lignes, le nombre de 'Views' sera beaucoup plus proche de 10 que 1,000. Probablement comme 12 ou 14. C'est le point de recyclage de ligne avec 'convertView', donc Android n'a pas à créer (et plus tard GC) tout un tas de widgets de ligne. – CommonsWare

5

Pour clarifier davantage la réponse de CommonsWare, voici quelques informations supplémentaires:

Le li.inflate opération (nécessaire ici pour l'analyse de la mise en page d'une ligne de XML et la création de l'objet View approprié) est enveloppé par un if (convertView == null) déclaration pour l'efficacité, de sorte que le gonflage du même objet ne se reproduira pas encore et encore chaque fois qu'il apparaît en vue. Toutefois, les autres parties de la méthode getView sont utilisées pour définir d'autres paramètres et ne doivent donc PAS être incluses dans l'instruction if (convertView == null) {} ... else {}.

Dans beaucoup la mise en œuvre commune de cette méthode, certaines étiquettes textView, éléments ImageView ou ImageButton doit être constituée par des valeurs de la liste [position], en utilisant findViewById et après que .setText ou .setImageBitmap opérations . Ces opérations doivent venir après à la fois en créant une vue de zéro par inflation et en obtenant une vue existante sinon null (par exemple sur un rafraîchissement).

Un autre bon exemple où cette solution est appliquée pour une ListView ArrayAdapter apparaît dans https://stackoverflow.com/a/3874639/978329

Questions connexes