方向更改时无法在片段中保存 recyclerview 的实例状态

Cannot save instance state for recyclerview in fragment when orientation change

我无法让我的 recyclerview 保存方向更改的状态。在我的片段中使用了 onSaveInstanceState 但显然不正确,因为它不起作用。关于如何修复的任何建议和指示?

第二个活动

public class SecondActivity extends AppCompatActivity {


private boolean mTwoPane;
ArrayList<Recipe> myList;
List<Steps> steps;
android.support.v7.app.ActionBar actionBar;
StepsFragment fragment;

//Eventbus
@Override
protected void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}


@Override
protected void onStop() {
    super.onStop();
    EventBus.getDefault().unregister(this);
}


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main_two);


    actionBar = getSupportActionBar();
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    getSupportActionBar().setHomeButtonEnabled(true);


    myList = getIntent().getParcelableArrayListExtra("list");
    String id = getIntent().getStringExtra("intent");
    int result = Integer.parseInt(id);
    steps = (ArrayList) myList.get(result - 1).getSteps();

    String nameString = myList.get(result - 1).getName();

    getSupportActionBar().setTitle(nameString);


    if (findViewById(R.id.android_me_linear_layout) != null) {

        mTwoPane = true;

        if (savedInstanceState == null) {

            Bundle arguments = new Bundle();


            arguments.putParcelableArrayList("myList", myList);
            arguments.putInt("result", result);
            arguments.putBoolean("twoPane", mTwoPane);

            StepsFragment fragment = new StepsFragment();

            fragment.setArguments(arguments);

            getSupportFragmentManager().beginTransaction()
                    .add(R.id.fragment_container, fragment)
                    .commit();


        }



    } else {
        // We're in single-pane mode and displaying fragments on a phone in separate activities
        mTwoPane = false;

        Bundle arguments = new Bundle();


        arguments.putParcelableArrayList("myList", myList);
        arguments.putInt("result", result);
        arguments.putBoolean("twoPane", mTwoPane);

        StepsFragment fragment = new StepsFragment();

        fragment.setArguments(arguments);

        getSupportFragmentManager().beginTransaction()
                .add(R.id.fragment_container, fragment)
                .commit();



    }


}


@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            onBackPressed();
            return true;
    }
    return super.onOptionsItemSelected(item);
}

@Override
public void onBackPressed() {
    super.onBackPressed();
    if(mTwoPane) {


        startActivity(new Intent(SecondActivity.this, MainActivity.class));
        finish();
    }

}

@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(Message event) {

    if (event.getMessage() == 2) {


        Fragment newFragment = new DetailFragment();

        newFragment.setArguments(event.getBundle());

        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        transaction.replace(R.id.detail_container, newFragment);


        transaction.addToBackStack(null);

        transaction.commit();

        Log.d(LOG_TAG, "Eventbus worked");


    }

    else if ( event.getMessage() == 3){

        Fragment newFragment = new DetailFragment();

        newFragment.setArguments(event.getBundle());

        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        transaction.replace(R.id.fragment_container, newFragment);

        transaction.addToBackStack(null);

        transaction.commit();



    }


}

}

StepsFragment

public class StepsFragment extends android.support.v4.app.Fragment {



ArrayList<Recipe> myList;
List<Steps> myStepsList;
List <Ingredients> ingredients;

private RecyclerView recyclerView;
StepItemRecyclerViewAdapter stepItemRecyclerViewAdapter;
private RecyclerView.LayoutManager mLayoutManager;

int result;
List<String> ingredientsString;
String string;
Boolean mTwoPane;
Parcelable listState;

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putParcelableArrayList("myArrayListTwo",(ArrayList) myStepsList);
}


@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);


    if(savedInstanceState == null || !savedInstanceState.containsKey("myArrayListTwo")){
        myStepsList = new ArrayList<>();
    }

    else{
        myStepsList = savedInstanceState.getParcelableArrayList("myArrayListTwo");
    }


    mTwoPane = getArguments().getBoolean("twoPane");
    myList = getArguments().getParcelableArrayList("myList");
    result = getArguments().getInt("result") - 1;
    myStepsList = myList.get(result).getSteps();
    ingredients = myList.get(result).getIngredients();


    //Create a String array for all ingredients strings
    ingredientsString = new ArrayList<>();
    ingredientsString.add("Ingredients" + "\n");

    for(int x = 0; x < ingredients.size(); x++){

        ingredientsString.add(ingredients.get(x).getIngredient() + " " + ingredients.get(x).getQuantity() + " " + ingredients.get(x).getMeasure());
        Log.d(LOG_TAG, ingredientsString.get(x).toString());
    }



    StringBuilder stringBuilder = new StringBuilder();
    for(String s : ingredientsString){
        stringBuilder.append(s + "\n");
    }

    string = stringBuilder.toString();



}



@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View rootView = inflater.inflate(R.layout.fragment_steps, container, false);

        recyclerView = (RecyclerView) rootView
                .findViewById(R.id.my_recycler_view);

        mLayoutManager = new LinearLayoutManager(getActivity());

        recyclerView.setLayoutManager(mLayoutManager);
        stepItemRecyclerViewAdapter = new StepItemRecyclerViewAdapter(myStepsList);
        recyclerView.setAdapter(stepItemRecyclerViewAdapter);


        TextView textView = (TextView) rootView.findViewById(R.id.text_view);
        textView.setText(string);


    return rootView;
}


public class StepItemRecyclerViewAdapter
        extends RecyclerView.Adapter<StepItemRecyclerViewAdapter.ViewHolder> {

        private final List<Steps> mValues;



    public StepItemRecyclerViewAdapter(List<Steps> items) {

        mValues = items;
    }

    @Override
    public StepItemRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_list_content, parent, false);
        return new StepItemRecyclerViewAdapter.ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final StepItemRecyclerViewAdapter.ViewHolder holder, int position) {


        holder.mItem = mValues.get(position);


        holder.mContentView.setText(mValues.get(position).getShortDescription());




        holder.mView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {


                if(mTwoPane){
                    Bundle args = new Bundle();

                    args.putParcelableArrayList("myList", myList);
                    args.putInt("result", result);
                    args.putString("int", holder.mItem.getId());
                    EventBus.getDefault().postSticky(new Message(2, args));
                    Log.d(LOG_TAG, "You clicked a button" + holder.mItem.toString());



                } else if( mTwoPane == false){

                    Bundle args = new Bundle();

                    args.putParcelableArrayList("myList", myList);
                    args.putInt("result", result);
                    args.putString("int", holder.mItem.getId());
                    EventBus.getDefault().postSticky(new Message(3, args));
                    Log.d(LOG_TAG, "You clicked a button" + holder.mItem.toString());

                }


            }
        });
    }

    @Override
    public int getItemCount() {
        return mValues.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        public  View mView;
        public TextView mContentView;
        public Steps mItem;


        public ViewHolder(View view) {
            super(view);
            mView = view;
            mContentView = (TextView) view.findViewById(R.id.content);

        }

        @Override
        public String toString() {
            return super.toString() + " '" + mContentView.getText() + "'";
        }
    }
}













}

activity_main_two.xml https://github.com/RJRogers/TwoPaneUITest/blob/master/app/src/main/res/layout/activity_main_two.xml

fragment_steps.xml https://github.com/RJRogers/TwoPaneUITest/blob/master/app/src/main/res/layout/fragment_steps.xml

您可以在 Manifest 文件的 activity 中添加这一行

android:configChanges="orientation|screenSize"

我从你发布的代码中跳出来的是这个(在你的 activity 中):

if (findViewById(R.id.android_me_linear_layout) != null) {
    if (savedInstanceState == null) {
        ...
        getSupportFragmentManager().beginTransaction()
                                   .add(R.id.fragment_container, fragment)
                                   .commit();
    }
}
else {
    ...
    getSupportFragmentManager().beginTransaction()
                               .add(R.id.fragment_container, fragment)
                               .commit();
}

一般来说,当 savedInstanceState 为 null 时,您只需添加一次片段,无论方向如何。即使 activity 的布局发生变化,片段管理器也会自动保存和恢复片段(只要两个布局都有一个具有相同 ID 的容器)。这可能导致出现新的片段,而不是已经保存和恢复状态的片段。

另一件突出的事情是这个(在你的片段中):

if(savedInstanceState == null || !savedInstanceState.containsKey("myArrayListTwo")){
    myStepsList = new ArrayList<>();
}
else{
    myStepsList = savedInstanceState.getParcelableArrayList("myArrayListTwo");
}
...
myStepsList = myList.get(result).getSteps();

您似乎不小心用基于片段参数包的新列表覆盖了保存的列表。我不能完全理解这个 fragment/activity 试图做什么,但这似乎是隐藏你的问题的一个合理的地方。