I have a long ListView
that the user can scroll around before returning to the previous screen. When the user opens this ListView
again, I want the
Neither of the solutions offered here seemed to work for me. In my case, I have a ListView
in a Fragment
which I'm replacing in a FragmentTransaction
, so a new Fragment
instance is created each time the fragment is shown, which means that the ListView
state can not be stored as a member of the Fragment
.
Instead, I ended up storing the state in my custom Application
class. The code below should give you an idea how this works:
public class MyApplication extends Application {
public static HashMap parcelableCache = new HashMap<>();
/* ... code omitted for brevity ... */
}
public class MyFragment extends Fragment{
private ListView mListView = null;
private MyAdapter mAdapter = null;
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mAdapter = new MyAdapter(getActivity(), null, 0);
mListView = ((ListView) view.findViewById(R.id.myListView));
Parcelable listViewState = MyApplication.parcelableCache.get("my_listview_state");
if( listViewState != null )
mListView.onRestoreInstanceState(listViewState);
}
@Override
public void onPause() {
MyApplication.parcelableCache.put("my_listview_state", mListView.onSaveInstanceState());
super.onPause();
}
/* ... code omitted for brevity ... */
}
The basic idea is that you store the state outside the fragment instance. If you don't like the idea of having a static field in your application class, I guess you could do it by implementing a fragment interface and storing the state in your activity.
Another solution would be to store it in SharedPreferences
, but it gets a bit more complicated, and you would need to make sure you clear it on application launch unless you want the state to be persisted across app launches.
Also, to avoid the "scroll position not saved when first item is visible", you can display a dummy first item with 0px
height. This can be achieved by overriding getView()
in your adapter, like this:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if( position == 0 ) {
View zeroHeightView = new View(parent.getContext());
zeroHeightView.setLayoutParams(new ViewGroup.LayoutParams(0, 0));
return zeroHeightView;
}
else
return super.getView(position, convertView, parent);
}