How to maintain ListView position when using the new Loader APIs?
Asked Answered
L

2

10

In Honeycomb the Loader APIs were introduced as the proper way to provide data to an application by doing the heavy lifting on a background thread. In my application I'm working to replace all my Cursors with Loaders that return Cursors. Since Cursor.requery() is depreciated now, it is recommended to just call restartLoader and allow the work to again be done on a background thread and then changeCursor when it returns in onLoadFinished.

All of this works wonderfully except that the ListView doesn't maintain it's scroll position when I want to requery the data, using Cursor.requery() this used to work because it was the same Cursor instance with updated data.

How can I refresh my Loader without loosing the scroll position?

Laux answered 28/8, 2011 at 0:11 Comment(1)
You could use getScrollX() and getScrollY() to cache it before you refresh, and then manually set it again. I'm not sure if this would result in visual flashing or other unpleasantness. :-/Bulger
L
6

The Loader class by itself doesn't know when the dataset changes and is implementation specific to CursorLoader currently. Now inside my application the data I needed to refresh is inside a local SQLite database (no ContentProvider) so I had to modify the CursorLoader to use my local database instead, as Dianne Hackborne mentioned on the developer group.

Unfortunately just returning a Cursor from loadInBackground doesn't allow the ContentObserver to properly notify the Loader when the data changes, this is because AbstractCursor only calls notifyChanged() when requery() is called on the Cursor.

Since the ContentObserver will never notify the Loader that the data has changed, I ended up calling Loader.onContentChanged() myself as needed. At this point it everything seems to be working but I'll update this answer if any significant issues arrise.

Laux answered 28/8, 2011 at 8:12 Comment(0)
P
1

You must just do not create a new adapter in each Loaders loading; I mean..

@Override
    public void onLoadFinished(Loader<List<NotificationItem>> loader, List<NotificationItem> notifications) {
        // We must do it in this way to not losing listview scroll position after a reload.
        if(mAdapter==null) {
            mAdapter = new HomeUserActivityListAdapter(getActivity(), notifications);
            mListView.setAdapter(mAdapter);

        }else{
            mAdapter.refill(notifications);
        }
    }

And in you adapter create a method to items refill

public void refill(List<NotificationItem> notifications) {
    mNotificationsList.clear();
    mNotificationsList.addAll(notifications);
    notifyDataSetChanged();
}

And that's all, it will maintain your scroll position exactly :-)

Pulver answered 16/2, 2015 at 10:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.