How to Save and Restore the Scroll Position and State of a Android ListView

If you are developing an Android app, you probably ran into Android ListViews. ListViews are a very capable, but also sometimes a challenging component. As an active Android user I see a common problem in many Android apps: they lose the scroll progress I made on a ListView after returning from a different view or restarting the app. Some apps at least restore the ListView to the general area, but not pixel-perfect. In this guide, I will outline three different approaches.

Two Possible but Flawed Solutions

If you research the issue, most guides will tell you to figure out the position of the first item, which is visible on the ListView with listView.getFirstVisiblePosition();. I will not post the entire code here, since it has a major drawback: it is inaccurate. A ListView item, which is only partially visible at the top, will be ignored. When restoring the ListView using the first visible position, the ListView will usually make a small jump up. Slightly irritating and confusing for the user.

Thus, some suggest to calculate the distance of the first ListView item to the top and then save the value in combination with getFirstVisiblePosition(). While this might lead to the desired result, it is neither the Android-way of doing things, nor nice and clean code.

The Final and Optimal Solution

The best solution is to use the pre-defined implementation, which unfortenately is not very established in the Android community. Once again, the best answer is buried on StackOverflow and not even marked as correct solution. The code to save the ListView state:

// Save the ListView state (= includes scroll position) as a Parceble
Parcelable state = listView.onSaveInstanceState();  

The code to restore the ListView state, including scroll position:

// Restore previous state (including selected item index and scroll position)
listView.onRestoreInstanceState(state);  

You can use these two snippets to correctly manage ListViews throughout the activity or fragment lifecycle. Additionally, if you need to set a new adapter, you can hold on to the scroll position:

// Save the ListView state (= includes scroll position) as a Parceble
Parcelable state = listView.onSaveInstanceState();

// e.g. set new items
listView.setAdapter(adapter);

// Restore previous state (including selected item index and scroll position)
listView.onRestoreInstanceState(state);  

I hope you can use this little guide to improve the user experience of your app. You can always find us on twitter for feedback and questions: @futurestud_io.


Explore the Library

Find interesting tutorials and solutions for your problems.

Miscellaneous