无法在设备旋转时使用 onSaveInstanceState() 和 onRestoreInstanceState()



我是Android开发的初学者。我试图在LayoutManager上使用onSaveInstanceState((和onRestoreInstanceState((来保存RecyclerView的LayoutManager的状态(在经历了很多StackOverflow问题之后(,但我无法这样做。我希望在设备旋转时恢复回收器视图的滚动位置。我也尝试保存布局中使用的嵌套滚动视图的位置,但也无法使其正常工作。

片段类

public class RecipeDetailFragment extends Fragment {
private static final String BUNDLE_RECIPE_ID = "Recipe";
private static final String BUNDLE_LAYOUT_MANAGER_KEY = "layout";
public StepAdapter mStepAdapter;
public IngredientAdapter mIngredientAdapter;
private Recipe selectedRecipe;
private StepAdapter.StepAdapterOnClickHandler mClickHandler;
@BindView(R.id.rv_recipe_detail_steps)
RecyclerView mStepRecyclerView;
@BindView(R.id.rv_recipe_detail_ingredients)
RecyclerView mIngredientRecyclerView;

public RecipeDetailFragment() {
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_recipe_detail, container, false);
ButterKnife.bind(this, rootView);
mIngredientAdapter = new IngredientAdapter();
mIngredientRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mIngredientRecyclerView.setHasFixedSize(true);
mIngredientRecyclerView.setNestedScrollingEnabled(false);
mStepAdapter = new StepAdapter(getContext(), mClickHandler);
mStepRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mStepRecyclerView.setHasFixedSize(true);
mStepRecyclerView.setNestedScrollingEnabled(false);
if (savedInstanceState != null) {
selectedRecipe = savedInstanceState.getParcelable(BUNDLE_RECIPE_ID);
}
mIngredientAdapter.setIngredientData(selectedRecipe.getIngredients());
mStepAdapter.setStepData(selectedRecipe.getSteps());
mIngredientRecyclerView.setAdapter(mIngredientAdapter);
mStepRecyclerView.setAdapter(mStepAdapter);
return rootView;
}
@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
if (savedInstanceState != null) {
Parcelable state = savedInstanceState.getParcelable(BUNDLE_LAYOUT_MANAGER_KEY);
mStepRecyclerView.getLayoutManager().onRestoreInstanceState(state);
}
}

public void setRecipe(Recipe recipe) {
selectedRecipe = recipe;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mClickHandler = (StepAdapter.StepAdapterOnClickHandler) context;
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(BUNDLE_RECIPE_ID, selectedRecipe);
outState.putParcelable(BUNDLE_LAYOUT_MANAGER_KEY, mStepRecyclerView.getLayoutManager()
.onSaveInstanceState());
}
}

布局

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/recipe_detail_nested_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:descendantFocusability="beforeDescendants"
android:fillViewport="true"
android:focusableInTouchMode="true">

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/ll_recipe_detail_scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="beforeDescendants"
android:fillViewport="true"
android:focusableInTouchMode="true"
android:orientation="vertical">
<android.support.v7.widget.CardView xmlns:cardView="http://schemas.android.com/apk/res-auto"
android:id="@+id/ingredients_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
android:layout_marginTop="8dp"
cardView:cardCornerRadius="4dp"
cardView:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_recipe_detail_ingredients_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="8dp"
android:text="@string/label_ingredients"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Widget.ActionMode.Title"
android:textSize="28sp" />
<android.support.v7.widget.RecyclerView xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/rv_recipe_detail_ingredients"
android:layout_width="match_parent"
android:focusable="false"
android:layout_height="match_parent"
android:paddingBottom="8dp" />
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView xmlns:cardView="http://schemas.android.com/apk/res-auto"
android:id="@+id/steps_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
android:layout_marginTop="8dp"
cardView:cardCornerRadius="4dp"
cardView:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_recipe_detail_steps_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="8dp"
android:paddingBottom="16dp"
android:text="@string/label_steps"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Widget.ActionMode.Title"
android:textSize="28sp" />
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_recipe_detail_steps"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="false"
android:paddingBottom="16dp" />
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>

附言这是我第一次在这里发布问题,所以如果我没有正确发布问题,请告诉我!

当您使用片段时,请确保在托管片段的活动中保存实例状态不为空时不执行片段事务,因为重新创建旋转活动 首先,您需要将传递给适配器的数据保存在 savedInstanceState 中,如果 savedInstanceState 不为 null,则使用该数据

并使用此自定义回收器视图

package eu.f3rog.ui.custom;
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();
}
}

只要您的RecyclerView设置了id,就不必执行任何操作来让它在旋转设备时保存其滚动状态。这是一个非常简单的应用程序来演示这一点。

主活动.java:

public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recycler = (RecyclerView) findViewById(R.id.recycler);
recycler.setAdapter(new MyAdapter());
}
private static class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View itemView = inflater.inflate(R.layout.itemview, parent, false);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.text.setText("" + position);
}
@Override
public int getItemCount() {
return 100;
}
}
private static class MyViewHolder extends RecyclerView.ViewHolder {
private final TextView text;
public MyViewHolder(View itemView) {
super(itemView);
this.text = (TextView) itemView.findViewById(R.id.text);
}
}
}

activity_main.xml:

<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="android.support.v7.widget.LinearLayoutManager"/>

项目视图.xml:

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_android_black_24dp"/>
<TextView
android:id="@+id/text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="12dp"
android:layout_marginStart="12dp"
android:textSize="14sp"
tools:text="Hello world"/>
</LinearLayout>

最新更新