0

This type of question is asked many times in SO, I have tried all of them, but couldn't achieve what I actually want. In my app I have Fragment, inside that fragment I have a recycler view. recyclerview would be manipulated by the data which I have got from API.

What I want that when rotation is changed, the app doesn't call the API again. To achieve this I know I have to put the data in onSaveInstanceState, If I want to save a complex object then the class must be implements Parcelable. I have done everything that is recommended, but couldn't achieve what I want.

I am sharing my code here, I have created a simplified example.

Code for 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();
    }
}

layout file for 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>

Here is code for my data model 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];
        }
    };
}

My adapter class: 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);
        }
    }
}

Code for single row layout for adapter 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>

These are what I have done, and if change the orientation getTestModelList() method in my SimpleFragment is called again, which I want to avoid; in real app scenario this method will do some API call. I want to save the state of ArrayList<TestModel> testModelList.

halfer
  • 19,824
  • 17
  • 99
  • 186
Mithun Sarker Shuvro
  • 3,902
  • 6
  • 32
  • 64

3 Answers3

2

you need to save state of activity and check it before configuration

follow this code

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();
        }
}}}
Umar Ata
  • 4,170
  • 3
  • 23
  • 35
2

You can save Fragment instance like this in Fragment onCreate method for orientation change to save instance :

@Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
         // Set Instance true
        this.setRetainInstance(true);
    }
Burhanuddin Rashid
  • 5,260
  • 6
  • 34
  • 51
1

Android recreates your activity whenever the orientation changes. The reason behind this is you may need to change your layout but you can still achieve that with onConfigurationChanged() of the Activity or the Fragment I suggest you to add

android:configChanges="orientation|keyboardHidden|screenSize"

in your manifest file (refer to this and this). This will stop recreation of Activity on Confifuration changes.

Community
  • 1
  • 1
Abbas
  • 3,529
  • 5
  • 36
  • 64