3

I've read many suggestions on how to retain the current scroll position in a RecyclerView when the device is rotated. I now found out that when I use com.android.support:recyclerview-v7:23.0.+, the current position is actually saved in the savedInstanceState. It also seems to be restored, but it is only restored "somewhat correctly".

What I'm experiencing this this: I scroll to the bottom of my list in portrait mode, then I switch to landscape. The current position is restored correctly (of course, some items are not visible - I'd be able to continue scrolling)!

Without any further scrolling, I rotate back to portrait and the position restored is several items above the position I'd actually thought I'd have. The list is no longer scrolled to the bottom.

My question is: Is there anything else I can do to actually store and restore the correct scroll position?

This is the layout for the RecyclerView:

<android.support.v4.widget.SwipeRefreshLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/swipeLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="...">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/itemsView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical" />

</android.support.v4.widget.SwipeRefreshLayout>

This is the shortened layout for the single items:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingTop="8dp"
    android:paddingBottom="8dp"
    android:paddingLeft="12dp"
    android:paddingRight="12dp">

    <!-- This linear layout aligns type indicator to the left and text content to the right -->
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        ...

    </LinearLayout>

</LinearLayout>

The fragment that hosts the RecyclerView has the following code:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    View v = inflater.inflate(R.layout.calendar_fragment, container, false);
    ButterKnife.bind(this, v);

    mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            ...
        }
    });

    if (mLayoutManager == null)
    {
        mLayoutManager = new LinearLayoutManager(getActivity());
        mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
    }

    // Get cached information or access storage
    if (savedInstanceState != null)
    {
        // Initialize the area and the adapter from the saved state
        mArea = savedInstanceState.getParcelable("AREA");
        Entry[] entries = (Entry[])savedInstanceState.getParcelableArray("ITEMS");
        mDataAdapter = new MyAdapter(this, mArea, entries);
    }
    else
    {
        // Initialize the area and the adapter form scratch
        mArea = getAreaByPreference();
        mDataAdapter = new MyAdapter(this, mArea);
    }

    // Initialize the RecyclerView
    mItemsView.setHasFixedSize(true);
    mItemsView.setAdapter(mDataAdapter);
    mItemsView.setLayoutManager(mLayoutManager);

    return v;
}
Thorsten Dittmar
  • 55,956
  • 8
  • 91
  • 139
  • Have you tried saving the position and then use `void scrollToPosition (int position)` ? https://developer.android.com/reference/android/support/v7/widget/LinearLayoutManager.html#scrollToPosition(int) – Jonsmoke Sep 15 '16 at 16:46
  • No, I haven't tried that yet, as all other solutions I found suggested letting `LinearLayoutManager` do its thing saving and restoring its own state. – Thorsten Dittmar Sep 15 '16 at 16:50
  • have you seen this answer ? http://stackoverflow.com/a/29166336/3658819 – Jonsmoke Sep 15 '16 at 16:52
  • Yep, that's one of the ones I've tried. I'll try again in case I did something wrong... – Thorsten Dittmar Sep 15 '16 at 16:56
  • what doesnt work with [this](http://pastebin.com/a4pvm5jq) code? – pskink Sep 15 '16 at 17:46
  • @pskink As I said - neither with the answer to the question Jonsmoke linked nor with the default behaviour the correct position is restored when turning from portrait to landscape and back. While the position is retained in landscape mode, the wrong position is scrolled to when going back to portrait. – Thorsten Dittmar Sep 15 '16 at 17:59
  • @Jonsmoke Same behavior when I implement the solution in the answer you linked. As I said... – Thorsten Dittmar Sep 15 '16 at 17:59
  • no: i tested port -> land and land -> port and in both cases the position is preserved, android 4.4 kitkat, com.android.support:recyclerview-v7:24.2.0 – pskink Sep 15 '16 at 18:01
  • @pskink Well, it did *not* work until I updated to the latest version of all support libraries and build tools. Works out of the box now. – Thorsten Dittmar Sep 15 '16 at 18:11
  • 1
    gut, btw this answer you tried: http://stackoverflow.com/a/29166336/3658819 misused the API completly , i have no idea how it got 79 upvotes – pskink Sep 15 '16 at 18:15

1 Answers1

2

Turns out that after updating to the current API 24 and the latest support libraries everything works as desired by default with no further coding...

Thorsten Dittmar
  • 55,956
  • 8
  • 91
  • 139