2010-08-18 12 views
1

Je rencontre un problème avec un ListActivity. J'ai étendu ArrayAdapter et Overridden getView pour remplir les données pour chaque ligne. Je jette quelques données de ArrayList de ma carte dans un TextView.Hors de contrôle ListView

Mon problème est, lorsque je défile, le TextView de chaque ligne remplit avec du texte qui ne figure pas dans ses données correspondantes dans ArrayList. Ce que je veux dire est: dis que j'ai une rangée en haut de ma liste avec un TextView qui est rempli avec emptystring. Si je suis au bas de ma liste et que je vois une ligne avec un TextView rempli de "bob" et que je clique pour faire défiler vers le haut, la ligne en haut peut maintenant avoir "bob" dans son TextView, mais les données à cet index de ma ArrayList ne contient pas "bob". Il contient emptystring (en fait null). Si je continue à faire défiler vers le haut et vers le bas, les autres lignes vont peupler (ou effacer) avec des données qui ne correspondent pas à ce qui se trouve dans ArrayList de l'adaptateur.

Pour que cela se produise, je n'ai pas besoin de faire défiler le ListView rapidement. Cependant, il semble que plus je défile rapidement, plus les lignes sont corrompues.

Voici mon code. Je me rends compte que j'utilise findViewById chaque fois que getView est appelé, mais ce n'est pas la question. Je l'appelle contre convertView; donc ça devrait être saisir le bon TextView sur chaque ligne, oui?

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 

    // get the View for this list item 
    View v = convertView; 
    if (v == null) { 
     LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     v = vi.inflate(R.layout.layout_mylistlist_item, null); 
    } 

    // get the next object 
    MyListItem myItem = m_items.get(position); 

    // set up the list item 
    if (myItem != null) { 
     TextView txtName = (TextView) v.findViewById(R.id.mylist_name); 

     // set text 
     if (txtName != null && myItem.getName() != null) { 
      txtName.setText(myItem.getName()); 
     } 
    } 

    // return the created view 
    return v; 
} 
+0

Si je supprime myItem.getName()! = Null de l'if-block près du bas, le problème semble s'arrêter. Je ne comprends pas pourquoi. – Andrew

+0

J'ai eu exactement le même problème. J'ai supprimé la vérification 'if (v == null)' et cela fonctionne très bien – Falmarri

+0

La suppression de la commande getName()! = Null force le texte textView à être écrasé. la suppression de la vérification v == null recrée l'ensemble de la mise en page. Dans tous les cas, le texte est effacé.Voir ma réponse pour un correctif plus fiable et une explication complète – CodeFusionMobile

Répondre

2

Je pense que le problème est votre if (myItem! = Null) vérifiez en bas. Essayez d'ajouter une instruction else à ce bloc qui définit la textview sur un emptystring.

Comme si:

// set up the list item 
TextView txtName = (TextView) v.findViewById(R.id.mylist_name); 
if (myItem != null) { 
    // set text 
    if (txtName != null && myItem.getName() != null) { 
     txtName.setText(myItem.getName()); 
    } else 
    { 
     txtName.setText(""); 
    } 
} 
else 
{ 
    txtName.setText(""); 
} 

Le convertview aura toujours les anciennes données quand il est passé à vous. Vous devez l'écraser intentionnellement, même si vos données ne sont pas valides, ou conserver ses anciennes données.

+0

Ya, je pense que vous avez raison. Si je ne mets pas txtName à QUELQUE CHOSE, il aura d'anciennes données provenant d'une autre ligne. – Andrew

+0

Le vrai plaisir commence lorsque vous feuilletez une liste très rapidement et le recycleur ne peut pas suivre :) – CodeFusionMobile

1

Bourse ce

if (v == null) { 
     LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     v = vi.inflate(R.layout.layout_mylistlist_item, null); 
    } 

avec ce

if (v == null) { 
     LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     v = vi.inflate(R.layout.layout_mylistlist_item, parent, false); 
    } 

Vous devez passer "false" à la méthode inflate (...).

Si vous avez le temps, jetez un oeil à propos de Android ListView cette année la session E/S: http://code.google.com/events/io/2010/sessions/world-of-listview-android.html

Il vaut vraiment la peine de regarder ou au moins défiler sur les diapositives. Ils sont également en ligne.

En fonction de vos commentaires, permettez-moi de proposer un moyen de lier les données avec l'ArrayAdapter. Peut-être que cela résout votre problème.

public class MyTestArrayAdapter extends ArrayAdapter<MyDataModel>{ 
    private final int resourceId; 

    public MyTestArrayAdapter(Context context, int resourceId, List<MyDataModel> myDataModelList) { 
     super(context, resourceId, myDataModelList); 
     this.resourceId = resourceId; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     if(convertView == null){ 
     LayoutInflater inflater = (LayoutInflater)getContext().getSystemService.... 
     convertView = inflater.inflate(resourceId, parent, false); 
     } 

     MyDataModel modelObj = getItem(position); 

     TextView someDataView = convertView.findViewById(....); 
     someDataView.setText(modelObj.getDataText()); 
     ... 

     return convertView; 
    } 

} 

Je pense que vous n'avez pas besoin de transmettre vos données en tant que membre de votre ArrayAdapter. (Je n'ai pas essayé de compiler ni d'exécuter ceci, donc cela peut nécessiter un ajustement)

+0

La méthode inflate (int, ViewGroup) dans le type LayoutInflater n'est pas applicable pour les arguments (int, boolean) – Andrew

+0

Je pense que vous vouliez dire "v = vi.inflate (R.layout .layout_inbox_item, null, false); ". J'ai essayé cela aussi avec le même résultat. – Andrew

+0

désolé, l'a réparé. Vous devez également transmettre "parent". Je ne l'ai pas vu avant :) – Juri