简体   繁体   中英

Unable to Restore the Scroll Position in RecyclerView using LayoutManager

So, I have an EditText on which I have set onEditorActionListener, ie after the user enters the text and presses enter/search it will fetch the details and populate the recycler view accordingly.

Now in order to save the state on a configuration change I have wrote the following code -

Parcelable stateList;

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    //Saving instance of the state in Parcelable stateList
    stateList = recyclerView.getLayoutManager().onSaveInstanceState();
    outState.putParcelable(RETAIN_STATE, stateList);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);

    if(savedInstanceState!=null) {
        stateList = savedInstanceState.getParcelable(RETAIN_STATE);
        recyclerView.getLayoutManager().onRestoreInstanceState(stateList);
    }
}

But when I run this, and rotate the screen the recycler view does not restore the state from the stateList parcelable.

I am using MVP, so I'm setting the adapter in the callback of the presenter.

I was able to retain the state when we click on enter/search on the keyboard after the screen was rotated, so I tried this hack in the onRestoreInstanceState(), but I think there should be a better way to go about this.

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);

    if(savedInstanceState!=null) {
        //The hack!
        et_search.onEditorAction(EditorInfo.IME_ACTION_SEARCH);
        stateList = savedInstanceState.getParcelable(RETAIN_STATE);
        recyclerView.getLayoutManager().onRestoreInstanceState(stateList);
    }
}

Let me know if there is more information needed. Thanks in advance.

You don't really need to call onRestoreInstanceState on configuration change in LayoutManager because it'll be called automatically (all views have onSaveInstanceState and onRestoreInstanceState that's passed from life-cycle owner). Even if you want to - all you'll achieve with this is restore scroll position of views.

What you actually need to do is save data set/used in RecyclerView adapter and set it back when screen is rotated. And then call search(or filter, whatever) again.

You can let android handle the orientation changes for you if don't want to any custom stuff by overriding config change.eg hiding some view etc

<activity android:name=".mainpage.view.MainActivity" android:configChanges="orientation|screenSize|screenLayout" >

Include this in your manifest for that activity Further to save scroll position in recyler view on rotation you can use following gist to avoid duplicate code as you can use this custom recyclerview in your project wherever same feature required

 import android.content.Context; import android.os.Bundle; import android.os.Parcelable; import android.support.annotation.Nullable; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; /** * Class {@link StatefulRecyclerView} extends {@link RecyclerView} and adds position management on configuration changes. * * @author FrantisekGazo * @version 2016-03-15 */ public final class StatefulRecyclerView extends RecyclerView { private static final String SAVED_SUPER_STATE = "super-state"; private static final String SAVED_LAYOUT_MANAGER = "layout-manager-state"; private Parcelable mLayoutManagerSavedState; public StatefulRecyclerView(Context context) { super(context); } public StatefulRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public StatefulRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected Parcelable onSaveInstanceState() { Bundle bundle = new Bundle(); bundle.putParcelable(SAVED_SUPER_STATE, super.onSaveInstanceState()); bundle.putParcelable(SAVED_LAYOUT_MANAGER, this.getLayoutManager().onSaveInstanceState()); return bundle; } @Override protected void onRestoreInstanceState(Parcelable state) { if (state instanceof Bundle) { Bundle bundle = (Bundle) state; mLayoutManagerSavedState = bundle.getParcelable(SAVED_LAYOUT_MANAGER); state = bundle.getParcelable(SAVED_SUPER_STATE); } super.onRestoreInstanceState(state); } /** * Restores scroll position after configuration change. * <p> * <b>NOTE:</b> Must be called after adapter has been set. */ private void restorePosition() { if (mLayoutManagerSavedState != null) { this.getLayoutManager().onRestoreInstanceState(mLayoutManagerSavedState); mLayoutManagerSavedState = null; } } @Override public void setAdapter(Adapter adapter) { super.setAdapter(adapter); restorePosition(); } } 

Link to gist

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM