39

I am trying to implement an endless scroll listview but when I call notifyDataSetChanged() the whole list refreshes then the scroll position goes back to the top.

Is this the normal behavior? how can I make it simply add the items added without refreshing and keep the scroll position?

code511788465541441
  • 20,207
  • 61
  • 174
  • 298

5 Answers5

70

Such behaviour is not normal. Without seeing your code I can suggest following:

1) You are not calling notifyDataSetChanged() from the UI thread. The correct way:

runOnUiThread(new Runnable() {
    public void run() {
        adapter.notifyDataSetChanged();
    }
});

2) You accidentally or not are making a call to adapter.notifyDataSetInvalidated();

3) In your adapter you override the adapter.notifyDataSetChanged(); method and added instruction to go to top

4) If you're using a list to populate adapter - you supply new list every time, so adapter settings are refreshed. You should always supply the same list. However you can change it as much as you want. If you're resetting the list use list.clear instead of list = new ArrayList();

Here is an example of my adapter:

public class Adapter extends BaseAdapter {

    private Activity activity;
    private ArrayList<HashMap<String, String>> data;
    private static LayoutInflater inflater = null;
    public ImageLoader imageLoader;

    public MediaItemAdapter(Activity a, ArrayList<HashMap<String, String>> d) {
        activity = a;
        data = d;
        inflater = (LayoutInflater) activity
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        imageLoader = new ImageLoader(activity.getApplicationContext());
    }

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

    public Object getItem(int position) {
        return position;
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        View vi = convertView;
        if (convertView == null) {
            vi = inflater.inflate(R.layout.item_composer, null);
        }
        TextView title = (TextView) vi.findViewById(R.id.item_title); // title
        TextView price = (TextView) vi.findViewById(R.id.price);


        return vi;
    }


}

Call for adapter:

List myList = new ArrayList<HashMap<String, String>>();
Adapter ma = new Adapter(this, myList);

myList can be empty before adapter initialization.

Then do some operation with my list:

myList.add(someElement);
ma.notifyDataSetChanged();

if you need delete all items:

myList.clear();
ma.notifyDataSetChanged();

Such implementation is pretty endless, I saw more then 15 thousand elements without any problems.

Seraphim's
  • 11,736
  • 17
  • 80
  • 126
Yarh
  • 4,116
  • 4
  • 39
  • 88
  • Can you please take a look at http://stackoverflow.com/questions/27815882/scroll-position-jumps-to-previous-list-items-while-scrolling-up-in-custom-listvi – kittu88 Jan 07 '15 at 11:00
  • In my case it was the third problem. I was populating a brand new list and assigning it to the variable originally used with adapter because of which list within the adapter never got refreshed. – E Malik Jun 30 '16 at 21:47
  • Great post! Saved my sanity! – siniux Jul 15 '16 at 17:00
  • 1
    In my case, I was setting the adapter again and again. No,, if your adapter already set to listview, just notify it. – Ozan Nov 07 '17 at 07:42
  • +1 For adding ```ma.notifyDataSetChanged();``` You just saved my recycler from hanging, now what remains is to completely stop using araylist.clear() before refreshing. I think the best solution is to use ```DiffUtils``` – olajide Oct 17 '19 at 20:31
13

In my case the issue was that I was calling ListView.setAdapter(adapter) every time new data was set which also reset position and the view jumped to the top.

Removing redundant setAdapter(...) calls fixed it for me.

vir us
  • 7,517
  • 3
  • 43
  • 55
7

You can do it in another way, like this

int position = scrollView.getSelectedItemPosition();
notifyDataSetChanged();
scrollView.setSelection(position);
Ushal Naidoo
  • 2,666
  • 1
  • 21
  • 37
Abhishek Shukla
  • 1,244
  • 8
  • 11
2

If your adapter is subclassing ArrayList then calling adapter.clear() will call notifyDataSetChanged() causing the scroll position to be lost. Consider calling setNotifyOnChange(false) first to prevent this.

More information here: https://stackoverflow.com/a/14719538/383761

Community
  • 1
  • 1
Hugh Jeffner
  • 2,826
  • 3
  • 29
  • 31
1

@Yarth's answer helped I'll just add on one small problem that I've just found that caused this, if you call

listview.setVisibility(View.VISIBLE);

will also cause the whole list to be scrolled to the top.

Lee Boon Kong
  • 662
  • 1
  • 6
  • 16