RecyclerView存储/恢复活动之间的状态

时间:2015-01-30 12:53:49

标签: android listview android-recyclerview

我将ListViews迁移到RecyclerViews。使用listviews,我使用了here描述的常用技术来存储和恢复活动之间的滚动位置。

如何使用RecyclerViews做同样的事情? RecyclerView.onSaveInstanceState()似乎有protected访问权限,因此无法直接使用。

9 个答案:

答案 0 :(得分:80)

好的,那么回答我自己的问题。据我所知,由于它们已经将布局代码和视图回收代码(因此名称)分离,因此负责保持布局状态(并恢复它)的组件现在是您的recyclerview中使用的LayoutManager

因此,要存储您使用相同模式的状态,但是在布局管理器而不是Recyclerview:

protected void onSaveInstanceState(Bundle state) {
     super.onSaveInstanceState(state);

     // Save list state
     mListState = mLayoutManager.onSaveInstanceState();
     state.putParcelable(LIST_STATE_KEY, mListState);
}

onRestoreInstanceState()中的恢复状态:

protected void onRestoreInstanceState(Bundle state) {
    super.onRestoreInstanceState(state);

    // Retrieve list state and list/item positions
    if(state != null)
        mListState = state.getParcelable(LIST_STATE_KEY);
}

然后更新LayoutManager(我在onResume()中执行):

@Override
protected void onResume() {
    super.onResume();

    if (mListState != null) {
        mLayoutManager.onRestoreInstanceState(mListState);
    }
}

答案 1 :(得分:19)

我找到了更好的解决方案 - 此解决方案具有以下优势:

  1. 旋转电话
  2. 时保存并恢复RecyclerView状态
  3. 使用RecyclerView保存并恢复返回活动的RecyclerView状态(在其他活动显示时未被销毁 - 这意味着onRestoreInstanceState()不是{\ n}叫!!)
  4. <强> CODE

    public class ActivityItemList extends AppCompatActivity
    {
        private final String KEY_RECYCLER_STATE = "recycler_state";
        private RecyclerView mRecyclerView;
        private static Bundle mBundleRecyclerViewState;
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_list);//set to whatever layout name you have
    
            mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);//set to whatever view id you use
            // don't forget to set your adapter
        }
    
        @Override
        protected void onPause()
        {
            super.onPause();
    
            // save RecyclerView state
            mBundleRecyclerViewState = new Bundle();
            Parcelable listState = mRecyclerView.getLayoutManager().onSaveInstanceState();
            mBundleRecyclerViewState.putParcelable(KEY_RECYCLER_STATE, listState);
        }
    
        @Override
        protected void onResume()
        {
            super.onResume();
    
            // restore RecyclerView state
            if (mBundleRecyclerViewState != null) {
                Parcelable listState = mBundleRecyclerViewState.getParcelable(KEY_RECYCLER_STATE);
                mRecyclerView.getLayoutManager().onRestoreInstanceState(listState);
            }
        }
    }
    

答案 2 :(得分:10)

onPause()onResume()中使用此代码来保存和恢复滚动位置 -

private Parcelable recyclerViewState;
recyclerViewState = mrecyclerView.getLayoutManager().onSaveInstanceState();//save
mrecyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);//restore

答案 3 :(得分:5)

这是我的解决方案,它会恢复两个项目和RecyclerView位置

1)在onSaveInstanceState方法中保存Recycler视图状态

@Override
protected void onSaveInstanceState(Bundle outState) {
    Parcelable listState = myRecyclerView.getLayoutManager().onSaveInstanceState();
    // putting recyclerview position
    outState.putParcelable(SAVED_RECYCLER_VIEW_STATUS_ID, listState);
    // putting recyclerview items
    outState.putParcelableArrayList(SAVED_RECYCLER_VIEW_DATASET_ID,mDataset);
    super.onSaveInstanceState(outState);
}

2)在onCreate方法

中检查savedInstanceState Bundle
@Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState==null){
            getRemoteData(); // No saved data, get data from remote
        }else{
            restorePreviousState(); // Restore data found in the Bundle
        }
    }

3)如果屏幕已旋转,则恢复回收者视图数据

public void restorePreviousState(){
    // getting recyclerview position
    mListState = mSavedInstanceState.getParcelable(SAVED_RECYCLER_VIEW_STATUS_ID);
    // getting recyclerview items
    mDataset = mSavedInstanceState.getParcelableArrayList(SAVED_RECYCLER_VIEW_DATASET_ID);
    // Restoring adapter items
    mAdapter.setItems(mDataset);
    // Restoring recycler view position
    mRvMedia.getLayoutManager().onRestoreInstanceState(mListState);
}

答案 4 :(得分:1)

您可以使用adapter.stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY中引入的recyclerview:1.2.0-alpha02

https://medium.com/androiddevelopers/restore-recyclerview-scroll-position-a8fbdc9a9334

但是它有一些问题,例如不能与内部RecyclerView一起使用,还有一些其他问题,您可以在中篇文章的评论部分中查看。

或者您可以将ViewModelSavedStateHandle一起使用,这适用于内部RecyclerViews,屏幕旋转和进程死亡

使用ViewModel创建一个saveStateHandle

val scrollState=
    savedStateHandle.getLiveData<Parcelable?>(KEY_LAYOUT_MANAGER_STATE)

使用Parcelable scrollState来保存和恢复状态,如在其他帖子中所回答的那样,或者通过向RecyclerView添加滚动侦听器和

recyclerView.addOnScrollListener(object:RecyclerView.OnScrollListener(){

    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
        super.onScrollStateChanged(recyclerView, newState)
        if (newState == RecyclerView.SCROLL_STATE_IDLE) {
           // save here
        }
    }

答案 5 :(得分:0)

当您使用recyclerView.getLayoutManager().onSaveInstanceState()时,请勿忘记检查 null

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

    if (recyclerView != null) {
        outState.putParcelable(SCROLL_POSITION, recyclerView.getLayoutManager().onSaveInstanceState());
    }
}

答案 6 :(得分:0)

public class MainActivity extends AppCompatActivity {
Parcelable recyclerViewState;
.......
@Override
    protected void onPause() {
        super.onPause();
        recyclerViewState = MainAnecdotesView.getLayoutManager().onSaveInstanceState();//save
    }
    @Override
    protected void onResume()
    {
        super.onResume();
        if(recyclerViewState!=null)
            MainAnecdotesView.getLayoutManager().onRestoreInstanceState(recyclerViewState);//restore
    }
}

答案 7 :(得分:0)

我知道我迟到了,但如果它有帮助的话!

存储回收站视图位置比其他答案看起来要简单得多

你可以这样做

先创建一个成员变量

Parcelable state;

现在

@Override
protected void onPause() {
    super.onPause();
    state = recyclerView.getLayoutManager().onSaveInstanceState();
}

@Override
protected void onResume() {
    super.onResume();
    recyclerView.getLayoutManager().onRestoreInstanceState(state);
}

使用上面的代码覆盖暂停和恢复方法,你就可以开始了!!

答案 8 :(得分:-2)

考虑到您在代码中定义了RecyclerView(mRecyclerView)和LayoutManager(mLayoutManager)并且到目前为止一切正常,保存位置的解决方案(mPosition)您的RecyclerView看起来像这样:

  1. 使用的变量和常量:

    private final String RECYCLER_POSITION_KEY = "recycler_position";
    private int mPosition = RecyclerView.NO_POSITION;
    private RecyclerView mRecyclerView;
    private LinearLayoutManager mLayoutManager;
    private static Bundle mBundleState;
    
  2. onPause方法中:

    @Override
    protected void onPause()
    {
        super.onPause();
    
        // Save RecyclerView state
        mBundleState = new Bundle();
        mPosition = mLayoutManager.findFirstCompletelyVisibleItemPosition();
        mBundleState.putInt(RECYCLER_POSITION_KEY, mPosition);
    }
    
  3. onResume方法中:

    @Override
    protected void onResume()
    {
        super.onResume();
    
        // Restore RecyclerView state
        if (mBundleState != null) {
            mPosition = mBundleState.getInt(RECYCLER_POSITION_KEY);
            if (mPosition == RecyclerView.NO_POSITION) mPosition = 0;
            // Scroll the RecyclerView to mPosition
            mRecyclerView.smoothScrollToPosition(mPosition);
        }
    }
    
  4. onSaveInstanceState方法中:

    @Override
    public void onSaveInstanceState(Bundle outState) {
        // Save RecyclerView state
        outState.putInt(RECYCLER_POSITION_KEY,  mLayoutManager.findFirstCompletelyVisibleItemPosition());
    
        super.onSaveInstanceState(outState);
    }
    
  5. onRestoreInstanceState方法中:

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        // Restore RecyclerView state
        if (savedInstanceState.containsKey(RECYCLER_POSITION_KEY)) {
            mPosition = savedInstanceState.getInt(RECYCLER_POSITION_KEY);
            if (mPosition == RecyclerView.NO_POSITION) mPosition = 0;
            // Scroll the RecyclerView to mPosition
            mRecyclerView.smoothScrollToPosition(mPosition);
        }
    
        super.onRestoreInstanceState(savedInstanceState);
    }