2011-10-12 3 views
8

J'ai une activité Android dans laquelle j'ai un ListView lié à un ArrayAdapter personnalisé. Chaque ligne de ListView possède deux champs EditText (numériques).Android - EditTexts dans ListView lié à Custom ArrayAdapter - suivi des modifications

L'ArrayAdapter est initialement renseigné à partir d'un DB SQLite. Cependant, l'utilisateur peut ajouter une ligne à la fin de ListView, ou (en appuyant longuement sur une ligne) supprimer n'importe quelle ligne dans le ListView. Lorsqu'ils cliquent sur le bouton "Enregistrer", leurs modifications sont conservées. Je garde une trace des changements tels qu'ils sont faits en attachant un CustomTextWatcher pour l'événement AfterTextChanged() à chaque EditText dans la méthode getView() de ArrayAdapter (passant dans le EditText et l'objet correspondant dans la liste des éléments de ArrayAdapter) et puis définissant la propriété correspondante de cet objet au contenu de EditText. C'est ainsi que lors de l'enregistrement, je peux simplement parcourir la liste des objets sous-jacents et effectuer les changements de DB appropriés, sachant que la liste des objets est à jour.

Code de la classe de l'adaptateur et le CustomTextWatcher:

private class CustomAdapter extends ArrayAdapter<DataItem> { 
    private ArrayList<DataItem> items; 

    public CustomAdapter(Context context, int textViewResourceId, ArrayList<DataItem> items) { 
     super(context, textViewResourceId, items); 
     this.items = items; 
} 

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

      DataItem wed = items.get(position); 

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

      if(wed != null) 
      { 
        EditText text1 = (EditText) v.findViewById(R.id.text1); 
        EditText text2 = (EditText) v.findViewById(R.id.text2); 

       text1.addTextChangedListener(new CustomTextWatcher(text1,wed)); 
       text2.addTextChangedListener(new CustomTextWatcher(text2,wed)); 


       int weight = wed.getWeight(); 

       if(weight != -1) 
       { 
        text1.setText(weight+""); 
       } 


       int reps = wed.getReps(); 

       if(reps != -1) 
       { 
        text2.setText(reps+""); 
       } 


      } 

      return v; 
    } 

private class CustomTextWatcher implements TextWatcher { 

    private EditText EditText; 
    private DataItem item; 

    public CustomTextWatcher(EditText e, DataItem item) 
    { 
     this.EditText = e; 
     this.item = item; 
    } 

    @Override 
    public void afterTextChanged(Editable arg0) { 

     String text = arg0.toString(); 

     if(text != null && text.length() > 0) 
     { 
      int val; 

      try 
      { 
       val =Integer.parseInt(text); 
      } 

      catch(NumberFormatException e) 
      { 
       val=-1; 
      } 

      if(EditText.getId()==R.id.weightEditText) 
      { 
       item.setWeight(val); 
      } 

      else if(EditText.getId()==R.id.repsEditText) 
      { 
       item.setRepetitions(val); 
      } 
     } 
    } 

Tout cela fonctionne bien, sauf lorsque des éléments sont ajoutés ou supprimés lors de la duplication indésirable du contenu EditText arrive.

Pour illustrer par un exemple:

Commencez avec 3 rangs, tous de EditText vide
Dans la ligne 2, entrez '5', '6'
Cliquez sur 'Plus' -> Ajoute un (vide) rangée a la fin. Maintenant 4 rangs.
Supprimer la dernière ligne-> 3 lignes affichées, MAIS les 2ème et 3ème lignes affichent maintenant '5', '6' -> ???????

Il semble que la position relative des objets EditText dans ListView n'est pas stable après la reliure, ce qui cause le problème. Par exemple. L'objet EditText 'X' commence en position 3, puis après un rebind, il est en position 1 - mais un CustomTextWatcher y est toujours attaché en référence à l'objet de données en position 3. L'autre problème est le fait que addTextChangedListener() n'affecte pas les TextWatchers déjà attachés à EditText. Je suis assez nouveau sur Android, donc je ne suis pas sûr s'il y a une meilleure approche pour résoudre mon problème. Toute aide est appréciée.

Répondre

9

Il me semble qu'une classe personnalisée ('ViewHolder') était ce dont j'avais besoin pour garder les références entre un EditText et son objet de données associé correctement synchronisé sur chaque 'bind' des données. En outre, en plaçant les appels d'écouteur d'événement lorsque l'objet convertView était null dans la méthode getView(), un seul écouteur a été ajouté par objet EditText. Merci à http://www.vogella.de/articles/AndroidListView/article.html#listsactivity pour m'indiquer dans la bonne direction.

public class CustomAdapter extends ArrayAdapter<DataItem> { 
private ArrayList<DataItem> items; 
private Activity Context; 

public CustomAdapter(Activity context, int textViewResourceId, ArrayList<DataItem> items) { 
    super(context, textViewResourceId, items); 
    this.items = items; 
    this.Context = context; 
} 

static class ViewHolder { 
    protected EditText weight; 
    protected EditText reps; 

} 

public View getView(int position, View convertView, ViewGroup parent) { 
     View v = convertView; 

     DataItem wed = items.get(position); 


     if (v == null) { 
      LayoutInflater inflator = Context.getLayoutInflater(); 
      v = inflator.inflate(R.layout.log_exercise_row, null); 
      final ViewHolder viewHolder = new ViewHolder(); 
      viewHolder.text1 = (EditText) v.findViewById(R.id.text1); 
      viewHolder.text2 = (EditText) v.findViewById(R.id.text2); 


      viewHolder.text1.addTextChangedListener(new CustomTextWatcher(viewHolder, viewHolder.text1)); 
      viewHolder.text2.addTextChangedListener(new CustomTextWatcher(viewHolder, viewHolder.text2)); 

      v.setTag(viewHolder); 
      viewHolder.text1.setTag(wed); 
      viewHolder.text2.setTag(wed); 

     } 

     else 
     { 
      ViewHolder holder = (ViewHolder) v.getTag(); 
      holder.text1.setTag(wed); 
      holder.text2.setTag(wed); 
     } 

     ViewHolder holder = (ViewHolder) v.getTag(); 

     // set values 

     if(wed.getWeight() != -1) 
     { 
      holder.text1.setText(wed.getWeight()+""); 
     } 

     else 
     { 
      holder.weight.setText(""); 
     } 

     if(wed.getRepetitions() != -1) 
     { 
      holder.text2.setText(wed.getRepetitions()+""); 
     } 

     else 
     { 
      holder.reps.setText(""); 
     } 

     return v; 
} 
+0

disons que j'ai un nombre dynamique d'enfants, et que tous les enfants ont leur propre texte d'édition. Comment pouvons-nous créer et définir des observateurs de texte égaux aux enfants? THX – yfsx

Questions connexes