配置发生变化时,无法在android中保存片段状态

时间:2016-08-11 12:43:24

标签: android android-fragments parcelable android-savedstate

在SO中多次询问这类问题,我已经尝试了所有这些问题,但无法达到我真正想要的效果。在我的应用中,我有Fragment,在该片段中我有recycler视图,recyclerview将由我从API获取的数据操纵。我希望在轮换更改时,应用程序不会再次调用API。为了达到这个目的,我知道我必须将数据放在onSaveInstanceState中,如果我想保存一个复杂的对象,那么该类必须是实现Parcelable。我已经做了所有推荐的事情,但无法实现我想要的目标。

我在这里分享我的代码,我创建了一个简化的例子,我真正想做的事情。

SimpleFragment.java

的代码
public class SimpleFragment extends Fragment {

    RecyclerView recyclerView;
    ArrayList<TestModel> testModelList = new ArrayList<TestModel>() ;
    SimpleAdapter simpleAdapter;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.simple_fragment, container, false);
        recyclerView = (RecyclerView) rootView.findViewById(R.id.recycler);

        RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
        recyclerView.setLayoutManager(mLayoutManager);

        simpleAdapter = new SimpleAdapter(getActivity());

        recyclerView.setAdapter(simpleAdapter);


        if(savedInstanceState != null){
            //if this fragment starts after a rotation or configuration change, load the existing model from a parcelable
            testModelList = savedInstanceState.getParcelableArrayList("key");
            // I have done necessary debug , after rotation , it comes here ,
            // but suddenly savedInstanceState becomes null and getTestModelList() get called


        }else {
            //if this fragment starts for the first time, load the list of model
           getTestModelList();
        }

        simpleAdapter.setModel(testModelList);

        return rootView;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putParcelableArrayList("key",testModelList);
    }

    public void getTestModelList(){
        for (int i=0;i<10;i++){
            testModelList.add(new TestModel(i,"test"+i));
        }
        Toast.makeText(getActivity(),"Called",Toast.LENGTH_SHORT).show();
    }
}

SimpleFragment的布局文件: simple_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler"
        android:background="@android:color/black"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

以下是我的数据模型 TestModel.java

的代码
public class TestModel implements Parcelable {

    String text;

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public TestModel(int number, String text) {
        this.text = text;
    }


    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.text);
    }

    protected TestModel(Parcel in) {
        this.text = in.readString();
    }

    public static final Parcelable.Creator<TestModel> CREATOR
            = new Parcelable.Creator<TestModel>() {
        public TestModel createFromParcel(Parcel in) {
            return new TestModel(in);
        }

        public TestModel[] newArray(int size) {
            return new TestModel[size];
        }
    };
}

我的适配器类: SimpleAdapter.java

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

    Context context;
    ArrayList<TestModel> testModels;

    public SimpleAdapter(Context context) {
        this.context = context;
    }

    public void setModel(ArrayList<TestModel> model){
        this.testModels = model;
        notifyDataSetChanged();
    }

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

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.list_item.setText(testModels.get(position).getText());
    }

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

    public class ViewHolder extends RecyclerView.ViewHolder{
        TextView list_item;
        public ViewHolder(View itemView) {
            super(itemView);
            list_item = (TextView) itemView.findViewById(R.id.list_item);
        }
    }
}

适配器 single_row.xml

的单行布局代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="20dp"
        android:id="@+id/list_item"
        android:textColor="@android:color/white"/>

</LinearLayout>

这些是我所做的,如果再次调用我的SimpleFragment中的方向getTestModelList()方法,我想避免,在实际的应用场景中,此方法将执行一些API调用。我想保存ArrayList<TestModel> testModelList的状态。

任何帮助都将受到高度赞赏。提前谢谢。

3 个答案:

答案 0 :(得分:2)

您需要保存活动状态并在配置之前进行检查

按照此代码

public class MainActivity extends AppCompatActivity{


    private HomeFragment homeFragment;

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

        FragmentManager fm = getSupportFragmentManager();


           if (savedInstanceState == null) {
            homeFragment = new HomeFragment();


            ((fm.beginTransaction()).replace(R.id.mainframe, homeFragment)).commit();
        }
}}}

答案 1 :(得分:2)

您可以在Fragment onCreate方法中保存像这样的Fragment实例,以便更改方向以保存实例:

@Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
         // Set Instance true
        this.setRetainInstance(true);
    }

答案 2 :(得分:1)

Android会在方向发生变化时重新创建您的活动。这背后的原因是您可能需要更改布局,但仍然可以使用onConfigurationChanged()的{​​{1}}或Activity我建议您添加

Fragment

清单文件中的

(请参阅thisthis)。这将停止在Confifuration更改上重新创建活动。