18

I get duplicated items in a ListView. Scrolling back and down sometimes changes the item order. I googled and found many threads reporting this bug, but none of them helped me in fixing my issue.

Here is my code:

Activity:

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;
    }


}

By the way, the output is:

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

Regards, ProgVal

Valentin Lorentz
  • 9,556
  • 6
  • 47
  • 69

5 Answers5

34

Try this:

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;
    }
}

Explanation: you got the duplicates because lists on Android reuse UI objects. You are expected to reuse convertView rather than create a new one if it is not null. Of course, you are responsible to set an appropriate value to the instance being reused. Otherwise the value is left from the last "usage".

Vit Khudenko
  • 28,288
  • 10
  • 63
  • 91
  • Ok, I got it. I thought it was just reusing the object for the same item, and not others. However, the scrollbar now gets bigger and smaller when I scroll, depending of the height of the currently displayed item. – Valentin Lorentz Nov 25 '11 at 17:10
  • @Arhimed Can u please explain the "Explanation" part in more detail. I am stuck with this issue for a long time. – AbhishekB Mar 20 '13 at 11:57
  • 1
    @abhishekb: please check this for details - http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/ – Vit Khudenko Mar 20 '13 at 20:09
  • Thanks @Arhimed you saved my day. – Rahul Vats Sep 13 '16 at 12:25
5
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;
}
Chien_Khmt
  • 257
  • 2
  • 8
2

ListView does not guarantee uniqueness of items you are added there. It is your responsibility. You are using ArrayList to store items and it can store as many duplicate items as you want.

If you want to removed duplicates put your items into set and then into list again:

listMessages = new ArrayList<Messages>(new LinkedHashSet<Message>(listMessages))

The LinkedHashSet will remove duplicates preserving the initial order of items, ArrayList will allow access elements by position.

AlexR
  • 114,158
  • 16
  • 130
  • 208
0

A suggestion - add a log statement after title.setText and write the value obtained from getTitle(). You might get to know why you are getting duplicate entries.

user994886
  • 444
  • 4
  • 13
0

You should use the ViewHolder paradigma in your ListAdapter

a nice example can be found here: http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/view/List14.html

Michele
  • 6,126
  • 2
  • 41
  • 45
  • Whats to be done with Bind view new view, I tried the tag holder pattern and it still duplicates. – Skynet Dec 19 '13 at 08:50