Je reçois des éléments en double dans un ListView. Faire défiler en arrière change parfois l'ordre des éléments. J'ai cherché sur Google et trouvé de nombreux fils de discussion rapportant ce bogue, mais aucun d'entre eux ne m'a aidé à résoudre mon problème.
Voici mon code:
Activité:
package com.github.progval.SeenDroid;
import Java.util.ArrayList;
import Java.util.List;
import com.github.progval.SeenDroid.lib.Connection;
import com.github.progval.SeenDroid.lib.Message;
import com.github.progval.SeenDroid.lib.MessageFetcher;
import com.github.progval.SeenDroid.lib.Query.ParserException;
import Android.app.Activity;
import Android.app.ListActivity;
import Android.content.SharedPreferences;
import Android.os.Bundle;
public class ShowUserActivity extends ListActivity {
private Connection connection;
public ArrayList<Message> listMessages = new ArrayList<Message>();
public MessageAdapter adapter;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.profile);
this.connection = new Connection();
this.setTitle(R.string.homefeed_title);
this.listMessages = new MessageFetcher(this.connection).fetchUser();
this.bindUi();
}
private void bindUi() {
this.adapter = new MessageAdapter(this, this.listMessages);
this.setListAdapter(adapter);
// TODO Bind buttons
}
}
MessageAdapter:
package com.github.progval.SeenDroid;
import Java.util.ArrayList;
import Java.util.List;
import Java.util.Zip.Inflater;
import com.github.progval.SeenDroid.lib.Message;
import Android.content.Context;
import Android.text.Layout;
import Android.util.Log;
import Android.view.LayoutInflater;
import Android.view.View;
import Android.view.ViewGroup;
import Android.webkit.WebView;
import Android.widget.ArrayAdapter;
import Android.widget.BaseAdapter;
import Android.widget.LinearLayout;
import Android.widget.TextView;
public class MessageAdapter extends BaseAdapter {
private Context context;
private List<Message> items = new ArrayList<Message>();
private int lastPosition = 0;
public MessageAdapter(Context context, List<Message> items) {
super();
this.context = context;
this.items = items;
}
public View getView(int position, View convertView, ViewGroup parent) {
if (null == convertView) {
LinearLayout view;
view = (LinearLayout) LinearLayout.inflate(this.context, R.layout.message, null);
Log.d("SeenDroid", String.format("Get view %d", position));
TextView title = new TextView(view.getContext());
title.setText(this.items.get(position).getTitle());
view.addView(title);
return view;
} else {
return convertView;
}
}
@Override
public int getCount() {
return this.items.size();
}
@Override
public Object getItem(int location) {
return this.items.get(location);
}
@Override
public long getItemId(int arg0) {
return arg0;
}
}
À propos, le résultat est:
D/SeenDroid(30939): Get view 0
D/SeenDroid(30939): Get view 1
D/SeenDroid(30939): Get view 2
D/SeenDroid(30939): Get view 3
D/SeenDroid(30939): Get view 4
D/SeenDroid(30939): Get view 5
D/SeenDroid(30939): Get view 6
D/SeenDroid(30939): Get view 7
D/SeenDroid(30939): Get view 8
D/SeenDroid(30939): Get view 0
D/SeenDroid(30939): Get view 16
Cordialement, ProgVal
Essaye ça:
public View getView(int position, View convertView, ViewGroup parent) {
if (null == convertView) {
LinearLayout view = (LinearLayout) LinearLayout.inflate(this.context,
R.layout.message, null);
Log.d("SeenDroid", String.format("Get view %d", position));
TextView title = new TextView(view.getContext());
title.setText(this.items.get(position).getTitle());
view.addView(title);
return view;
} else {
LinearLayout view = (LinearLayout) convertView;
TextView title = (TextView) view.getChildAt(0);
title.setText(this.items.get(position).getTitle());
return convertView;
}
}
Explication : vous avez les doublons car les listes sur Android réutilisent les objets de l'interface utilisateur. Vous êtes censé réutiliser convertView
plutôt que d'en créer une nouvelle si elle n'est pas nulle. Bien entendu, vous êtes responsable de la définition d'une valeur appropriée pour l'instance en cours de réutilisation. Sinon, il reste la valeur de la dernière "utilisation".
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView;
if (convertView == null) {
gridView = new View(context);
} else {
gridView = (View) convertView;
}
gridView = inflater.inflate(R.layout.worker_listmain, null);
// your source code here!!! Run 100%
// I got this problem also, I found out the way to solve it!
// Please use my source code :D SIMPLE is PERFECT :D
return gridView;
}
ListView ne garantit pas l'unicité des éléments que vous y avez ajoutés. C'est ta responsabilité. Vous utilisez ArrayList
pour stocker des éléments, qui peuvent stocker autant d'éléments en double que vous le souhaitez.
Si vous souhaitez supprimer les doublons, placez vos éléments dans le jeu, puis dans la liste:
listMessages = new ArrayList<Messages>(new LinkedHashSet<Message>(listMessages))
La LinkedHashSet
supprimera les doublons en conservant l'ordre initial des éléments, ArrayList
permettra l'accès aux éléments par position.
Vous devez utiliser le paradigme ViewHolder dans votre ListAdapter
un bel exemple peut être trouvé ici: http://developer.Android.com/resources/samples/ApiDemos/src/com/example/Android/apis/view/List14.html
Une suggestion - ajoutez une instruction de journal après title.setText et écrivez la valeur obtenue à partir de getTitle (). Vous apprendrez peut-être pourquoi vous obtenez des entrées en double.