android - tutorial - listview adapter




Adaptateur ListView personnalisé. Appels TextChangedListener pour mauvais EditText (2)

J'ai la liste des voyageurs avec un adaptateur personnalisé qui consistent deux EditText - edtFirstName et edtLastName. Je veux quand l'utilisateur entre le texte sauve des changements à la liste, et quand le bouton suivant cliquent l'envoi de cette liste à une autre activité.

Mon code:

public class TravellersAdapter extends BaseAdapter {

  private List<Traveler> itemsList;
  private LayoutInflater inflater;
  private Activity context;

  public TravellersAdapter(Activity context, List<Traveler> itemsList) {
    super();
    this.itemsList = itemsList;
    this.context = context;
    inflater = LayoutInflater.from(context);
  }

  public int getCount() { return itemsList.size();  }

  public Object getItem(int i) {  return itemsList.get(i);  }

  public View getView(final int position, View view, ViewGroup viewGroup) {
    if (view == null) {
      view = inflater.inflate(R.layout.traveller_item, null);
    }
    Traveler currentItem = (Traveler) getItem(position);

    EditText firstNameView = (EditText) view.findViewById(R.id.edtFirstName);
    firstNameView.addTextChangedListener(new TextWatcher() {

      public void afterTextChanged(Editable editable) {
        currentItem.setFirstName(editable.toString());
      }

    });

    return view;
  }
}

Par exemple, les éléments de liste sont composés de 5 éléments. Quand j'édite 2-4 éléments tout va bien, mais quand j'édite la première ou la dernière valeur éditée d'élément assignée à tout l'élément dans la liste. Dans Dubugger j'ai vu cette méthode afterTextChanged appelle 5 fois avec différentes valeurs de position . Comment le réparer?


Le problème se produit parce que les vues sont réutilisables (c'est-à-dire par conception dans l'API Android). Donc, éventuellement, vous pouvez affecter plus d'un observateur de texte à la même vue de texte. Et tous les observateurs assignés sont tirés quand le texte à l'intérieur de la vue de texte est changé.

Une solution rapide (et non optimale si la liste est vraiment longue, disons de plus de 1000 éléments) serait d'avoir une carte de Traweller -> TextWatcher .

Ensuite, à l'intérieur de getView (), vous pouvez le faire (pseudo-code):

  • vérifier la carte s'il y a un TextWatcher pour ce Traweller
  • si map n'en a pas, alors créez un nouveau TextWatcher , mettez-le dans la map et assignez-le à EditText
  • sinon, détachez TextWatcher de EditText et supprimez de la carte
  • créer un nouveau TextWatcher , mettre dans la carte et assigner à EditText

Dans la méthode getView , la position du paramètre donne la position de l' enfant nouvellement créé, pas la position de l'enfant cliqué.

utilisez ceci pour obtenir la bonne position:

final int actual_position = myList.getPositionForView((View) v.getParent());

dans onClick(View v); de l' onClickListener de n'importe quelle vue. Dans votre cas, vous devez implémenter onTextChangedListener pour cet EditText.

ici:

myList est le ListView

v est la vue sur laquelle vous avez cliqué, dans ce cas, la vue enfant du parent (myList).







adapter