Retaining Position in Listview After Calling Notifydatasetchanged

Retaining position in ListView after calling notifyDataSetChanged

Could this be what you want?

// save index and top position
int index = mList.getFirstVisiblePosition();
View v = mList.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();

// notify dataset changed or re-assign adapter here

// restore the position of listview
mList.setSelectionFromTop(index, top);

EDIT 28/09/2017:

The API has changed quite a bit since 2015. It is similar, but now it would be:

// save index and top position
int index = mList.FirstVisiblePosition; //This changed
View v = mList.getChildAt(0);
int top = (v == null) ? 0 : v.Top; //this changed

// notify dataset changed or re-assign adapter here

// restore the position of listview
mList.setSelectionFromTop(index, top);

notifyDataSetChanged() makes the list refresh and scroll jumps back to the top

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.

How to fix notifyDataSetChanged/ListView problems in dynamic Adapter wrapper Android

The main problem with the approach presented above was that the data set was being changed directly from within code executed by the superclasses. By populating the headings in getView() I was changing the data in what could be the middle of an operation or an "unsafe" state in the superclasses. This is why all touch interaction broke when onNotifyDataSetChanged was called during a fling scroll. The data needs to be added from an external source, not from within the adapter methods.

That can be done by using a Handler or AsyncTask to add the headings to the adapter and call its notifyDataSetChanged. These will be run on a UI thread and will not interfere with the superclass state. Thanks to CommonsWare's EndlessAdapter example for introducing the concept of an AsyncTask to add data to a list.

The onTouchEvent() and layoutChildren() hacks were no longer needed after making that change.

how to maintain scroll position of listview when it updates

It is easier to maintain scroll position by calling notifydatasetchanged() only. The problem there is that you are creating a new adapter every time the data gets updated... you should do something like this:

if(listView.getAdapter()==null)
listView.setAdapter(myAdapter);
else{
myAdapter.updateData(myNewData); //update adapter's data
myAdapter.notifyDataSetChanged(); //notifies any View reflecting data to refresh
}

This way, your listview will mantain the scrolling position.

In case you want to scroll to a new position, use:

list.smoothScrollToPosition(int position);

How to remain at a scroll position in RecyclerView after adding items at its first index and call notifydatasetchange

There are two options:

  1. Use the more sophisticated versions of notify

    List newData = createLineItems(dataArrayList);
    mCurrentFragment.items.addAll(0, newData);
    notifyItemRangeInserted(0, newData.size());
  2. Use stable IDs. On your adapter override public long getItemId (int position) to make it return MEANINGFUL values and call setHasStableIds(true); on it.

Android ViewPager with ListView can not remember the last position when called notifyDatasetchanged

You can use this logic... before call dataSetChanged store this listview state in Parcelable varaiable and after dataSetChanged time for restore the listview from a value which you have strored in a parcelable variable
like this ..

   Parcelable scrollPos=listview.onSaveInstanceState();
// call your pagerAdapter.notifyDataSetChanged

if(scrollPos != null)
{
listview.onRestoreInstanceState(scrollPos);
}

there is another way i found it from here

    // save index and top position
int index = mList.getFirstVisiblePosition();
View v = mList.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();

// notify dataset changed or re-assign adapter here

// restore the position of listview
mList.setSelectionFromTop(index, top);


Related Topics



Leave a reply



Submit