无法使用 LayoutManager 恢复 RecyclerView 中的滚动位置

Unable to Restore the Scroll Position in RecyclerView using LayoutManager

所以,我有一个 EditText,我在其上设置了 onEditorActionListener,即在用户输入文本并按下 enter/search 后,它将获取详细信息并相应地填充回收器视图。

现在为了在配置更改时保存状态,我编写了以下代码 -

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);
    }
}

但是当我 运行 这样做并旋转屏幕时,回收器视图不会从 stateList parcelable 恢复状态。

我正在使用 MVP,所以我在演示者的回调中设置了适配器。

当我们在屏幕旋转后点击键盘上的 enter/search 时,我能够保持状态,所以我在 onRestoreInstanceState() 中尝试了这个 hack,但我认为应该有更好的方法去解决这个问题。

@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);
    }
}

如果需要更多信息,请告诉我。 提前致谢。

您真的不需要在 LayoutManager 中更改配置时调用 onRestoreInstanceState,因为它会自动调用(所有视图都有 onSaveInstanceStateonRestoreInstanceState,这是从生活中传递过来的-循环拥有者)。即使你想要 - 你将实现的只是恢复视图的滚动位置。

您实际需要做的是将数据 set/used 保存在 RecyclerView 适配器中,并在屏幕旋转时将其重新设置。然后再次调用搜索(或过滤器等)。

You can let android handle the orientation changes for you if don't want to any custom stuff by overriding config change.e.g 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