RecyclerView 存储/恢复活动之间的状态
RecyclerView store / restore state between activities
我正在将我的 ListView 迁移到 RecyclerView。对于列表视图,我使用 here 描述的常用技术来存储和恢复活动之间的滚动位置。
如何对 RecyclerView 做同样的事情? RecyclerView.onSaveInstanceState()
似乎有 protected
访问权限,因此不能直接使用。
好的,所以回答我自己的问题。据我了解,由于他们已经分离了布局代码和视图回收代码(因此得名),负责保持布局状态(并恢复它)的组件现在是您的回收视图中使用的 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);
}
}
在onPause()
和onResume()
中使用此代码保存和恢复滚动位置-
private Parcelable recyclerViewState;
recyclerViewState = mrecyclerView.getLayoutManager().onSaveInstanceState();//save
mrecyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);//restore
我找到了更好的解决方案 - 这个解决方案有以下好处:
- RecyclerView 状态在 phone
的 旋转时保存和恢复
- RecyclerView 状态在 返回 activity 时保存并恢复 RecyclerView(在显示另一个 activity 时未被破坏 - 这意味着
onRestoreInstanceState()
没有被调用!!)
代码
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);
}
}
}
这是我的解决方案,它恢复了项目和 RecyclerView 位置
1) 在 onSaveInstanceState 方法中保存回收器视图状态
@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);
}
考虑到您在代码中定义了一个 RecyclerView (mRecyclerView
) 和一个 LayoutManager (mLayoutManager
),并且到目前为止一切正常,保存位置的解决方案 (mPosition
) 你的 RecyclerView 看起来像这样:
使用的变量和常量:
private final String RECYCLER_POSITION_KEY = "recycler_position";
private int mPosition = RecyclerView.NO_POSITION;
private RecyclerView mRecyclerView;
private LinearLayoutManager mLayoutManager;
private static Bundle mBundleState;
在onPause
方法中:
@Override
protected void onPause()
{
super.onPause();
// Save RecyclerView state
mBundleState = new Bundle();
mPosition = mLayoutManager.findFirstCompletelyVisibleItemPosition();
mBundleState.putInt(RECYCLER_POSITION_KEY, mPosition);
}
在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);
}
}
在onSaveInstanceState
方法中:
@Override
public void onSaveInstanceState(Bundle outState) {
// Save RecyclerView state
outState.putInt(RECYCLER_POSITION_KEY, mLayoutManager.findFirstCompletelyVisibleItemPosition());
super.onSaveInstanceState(outState);
}
在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);
}
当您使用 recyclerView.getLayoutManager().onSaveInstanceState()
时,不要忘记检查 null:
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
if (recyclerView != null) {
outState.putParcelable(SCROLL_POSITION, recyclerView.getLayoutManager().onSaveInstanceState());
}
}
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
}
}
您可以使用 adapter.stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY
recyclerview:1.2.0-alpha02
中介绍的
https://medium.com/androiddevelopers/restore-recyclerview-scroll-position-a8fbdc9a9334
但它有一些问题,例如无法使用内部 RecyclerView,还有一些其他问题,您可以在 medium post 的评论部分查看。
或者您可以将 ViewModel
与 SavedStateHandle
结合使用,这适用于内部 RecyclerView、屏幕旋转和 进程死亡。
用 saveStateHandle
创建一个 ViewModel
val scrollState=
savedStateHandle.getLiveData<Parcelable?>(KEY_LAYOUT_MANAGER_STATE)
使用 Parcelable scrollState
来保存和恢复状态,如其他 post 中的回答或通过向 RecyclerView 添加滚动侦听器和
recyclerView.addOnScrollListener(对象:RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
// save here
}
}
我知道我迟到了,但如果它有帮助的话!
存储回收站视图位置比其他答案看起来更简单
以下是您的操作方法
首先创建一个成员变量
Parcelable state;
现在,
@Override
protected void onPause() {
super.onPause();
state = recyclerView.getLayoutManager().onSaveInstanceState();
}
@Override
protected void onResume() {
super.onResume();
recyclerView.getLayoutManager().onRestoreInstanceState(state);
}
使用上面的代码覆盖 on pause 和 on resume 方法,你就可以开始了!
我正在将我的 ListView 迁移到 RecyclerView。对于列表视图,我使用 here 描述的常用技术来存储和恢复活动之间的滚动位置。
如何对 RecyclerView 做同样的事情? RecyclerView.onSaveInstanceState()
似乎有 protected
访问权限,因此不能直接使用。
好的,所以回答我自己的问题。据我了解,由于他们已经分离了布局代码和视图回收代码(因此得名),负责保持布局状态(并恢复它)的组件现在是您的回收视图中使用的 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);
}
}
在onPause()
和onResume()
中使用此代码保存和恢复滚动位置-
private Parcelable recyclerViewState;
recyclerViewState = mrecyclerView.getLayoutManager().onSaveInstanceState();//save
mrecyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);//restore
我找到了更好的解决方案 - 这个解决方案有以下好处:
- RecyclerView 状态在 phone 的 旋转时保存和恢复
- RecyclerView 状态在 返回 activity 时保存并恢复 RecyclerView(在显示另一个 activity 时未被破坏 - 这意味着
onRestoreInstanceState()
没有被调用!!)
代码
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);
}
}
}
这是我的解决方案,它恢复了项目和 RecyclerView 位置
1) 在 onSaveInstanceState 方法中保存回收器视图状态
@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);
}
考虑到您在代码中定义了一个 RecyclerView (mRecyclerView
) 和一个 LayoutManager (mLayoutManager
),并且到目前为止一切正常,保存位置的解决方案 (mPosition
) 你的 RecyclerView 看起来像这样:
使用的变量和常量:
private final String RECYCLER_POSITION_KEY = "recycler_position"; private int mPosition = RecyclerView.NO_POSITION; private RecyclerView mRecyclerView; private LinearLayoutManager mLayoutManager; private static Bundle mBundleState;
在
onPause
方法中:@Override protected void onPause() { super.onPause(); // Save RecyclerView state mBundleState = new Bundle(); mPosition = mLayoutManager.findFirstCompletelyVisibleItemPosition(); mBundleState.putInt(RECYCLER_POSITION_KEY, mPosition); }
在
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); } }
在
onSaveInstanceState
方法中:@Override public void onSaveInstanceState(Bundle outState) { // Save RecyclerView state outState.putInt(RECYCLER_POSITION_KEY, mLayoutManager.findFirstCompletelyVisibleItemPosition()); super.onSaveInstanceState(outState); }
在
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); }
当您使用 recyclerView.getLayoutManager().onSaveInstanceState()
时,不要忘记检查 null:
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
if (recyclerView != null) {
outState.putParcelable(SCROLL_POSITION, recyclerView.getLayoutManager().onSaveInstanceState());
}
}
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
}
}
您可以使用 adapter.stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY
recyclerview:1.2.0-alpha02
https://medium.com/androiddevelopers/restore-recyclerview-scroll-position-a8fbdc9a9334
但它有一些问题,例如无法使用内部 RecyclerView,还有一些其他问题,您可以在 medium post 的评论部分查看。
或者您可以将 ViewModel
与 SavedStateHandle
结合使用,这适用于内部 RecyclerView、屏幕旋转和 进程死亡。
用 saveStateHandle
ViewModel
val scrollState=
savedStateHandle.getLiveData<Parcelable?>(KEY_LAYOUT_MANAGER_STATE)
使用 Parcelable scrollState
来保存和恢复状态,如其他 post 中的回答或通过向 RecyclerView 添加滚动侦听器和
recyclerView.addOnScrollListener(对象:RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
// save here
}
}
我知道我迟到了,但如果它有帮助的话!
存储回收站视图位置比其他答案看起来更简单
以下是您的操作方法
首先创建一个成员变量
Parcelable state;
现在,
@Override
protected void onPause() {
super.onPause();
state = recyclerView.getLayoutManager().onSaveInstanceState();
}
@Override
protected void onResume() {
super.onResume();
recyclerView.getLayoutManager().onRestoreInstanceState(state);
}
使用上面的代码覆盖 on pause 和 on resume 方法,你就可以开始了!