web-dev-qa-db-fra.com

Entrées dupliquées dans ListView

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

17
Valentin Lorentz

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".

32
Vit Khudenko
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;
}
4
Chien_Khmt

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. 

2
AlexR

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

0
Michele

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.

0
user994886