Android, Liste Carte renvoie mauvaise position dans getView
J'ai trouvé un mystérieux problème qui peut être un bug!
J'ai une liste dans mon fragment. Chaque ligne dispose d'un bouton. La liste ne devrait pas répondre à cliquer cependant boutons sont cliquables.
Afin d'obtenir le bouton est cliqué, j'ai créé un auditeur et de l'implémenter dans mon fragment. C'est le code de ma carte.
public class AddFriendsAdapter extends BaseAdapter {
public interface OnAddFriendsListener {
public void OnAddUserClicked(MutualFriends user);
}
private final String TAG = "*** AddFriendsAdapter ***";
private Context context;
private OnAddFriendsListener listener;
private LayoutInflater myInflater;
private ImageDownloader imageDownloader;
private List<MutualFriends> userList;
public AddFriendsAdapter(Context context) {
this.context = context;
myInflater = LayoutInflater.from(context);
imageDownloader = ImageDownloader.getInstance(context);
}
public void setData(List<MutualFriends> userList) {
this.userList = userList;
Log.i(TAG, "List passed to the adapter.");
}
@Override
public int getCount() {
try {
return userList.size();
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = myInflater.inflate(R.layout.list_add_friends_row, null);
holder = new ViewHolder();
Typeface font = Typeface.createFromAsset(context.getAssets(), "fonts/ITCAvantGardeStd-Demi.ttf");
holder.tvUserName = (TextView) convertView.findViewById(R.id.tvUserName);
holder.tvUserName.setTypeface(font);
holder.ivPicture = (ImageView) convertView.findViewById(R.id.ivPicture);
holder.btnAdd = (Button) convertView.findViewById(R.id.btnAdd);
holder.btnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e(TAG, "Item: " + position);
listener.OnAddUserClicked(userList.get(position));
}
});
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.tvUserName.setText(userList.get(position).getName());
imageDownloader.displayImage(holder.ivPicture, userList.get(position).getPhotoUrl());
return convertView;
}
public void setOnAddClickedListener(OnAddFriendsListener listener) {
this.listener = listener;
}
static class ViewHolder {
TextView tvUserName;
ImageView ivPicture;
Button btnAdd;
}
}
Quand je lance l'application, je peux voir mes lignes mais depuis, ma liste est longue et plus de 200 articles quand je goto milieu de la liste et cliquez sur un élément puis retourné position est mauvaise (c'est quelque chose comme 7, parfois 4, etc...).
Maintenant ce qu'est le mystère?
Si je l'active sur le point d'écouteur de liste de mon fragment et cliquez sur la ligne alors ligne correcte position sera affichée sur la ligne si je clique sur le bouton mauvaise position sera affichée.
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Log.e(TAG, "item " + position + " clicked.");
}
});
Résultat dans le logcat:
05-09 10:22:25.228: E/AddFriendsFragment(20296): item 109 clicked.
05-09 10:22:34.453: E/*** AddFriendsAdapter ***(20296): Item: 0
Toute suggestion serait la bienvenue. Grâce
- Où en êtes-vous la mise en œuvre de
OnAddUserClicked()
? Aussi, si vous utilisez un BaseAdapter etList<T>
vous pouvez simplifier votre carte en utilisantArrayAdapter
au lieu de cela, car il est essentiellement unList
et est conçu pour résoudre le problème exact de chargement d'un Tableau ou d'une Liste d'objets de données dans un AdapterView
Vous devez vous connecter pour publier un commentaire.
Parce que le
convertView
et titulaire sera recyclé à utiliser, déplacez votresetOnClickListener
de l'instruction if else:Ce n'est pas la meilleure solution pour que,parce qu'il y aura des problème de performance. Je vous suggère de créer une Carte de votre vue et de créer une nouvelle vue pour votre élément, puis juste utiliser le relatif vue pour chaque vue.
Je pense que ça va être une meilleure solution avec les meilleures performances:
Vous pouvez également gérer votre avis par vous-même. Créer chaque vue unique pour votre article, qui ne recyclent pas vue.
position
est des appels ultérieurs. Et ainsi il sera possible de faire la même chose juste en passant le long d'un des différents utilisateurs de l'objet sur la base duposition
qui a été transmis getView().if (convertView == null) {
, de sorte que la position sera pas défini siconvertView
pas null. il s'est passé à chaque fois quand listview recycler les convertview. Au moins nous avons besoin de mettre l'ensemble de l'est d'autre instruction, afin que nous puissions avoir la bonne position.Avez-vous essayé de faire quelque chose comme ceci:
Puis récupérer des qui ligne a cliqué dans la fonction de rappel pour le bouton, comme ceci:
onClickListener = new View.OnClickListener(...)
et l'assigner à un bouton (si nombreux).Une autre approche que j'ai trouvé utile (si vous utilisez le ViewHolder modèle bien sûr) est de mettre l'index sur un attribut distinct à chaque fois que getView() est appelée, à l'intérieur de votre onClickListener vous avez juste à faire référence à votre titulaire de la position de l'attribut, quelque chose comme ceci: