Search code examples
androidandroid-recyclerviewparcelable

Why is this implementation of parcelables to save and restore Custom Arraylist not Working


I am fetching data from json with Volley and populating RecyclerView with the parsed data but I ran into a bit of problem: The call to get the items is in onCreate method, so the call is repeated each time the activity is recreated both from configuration changes and otherwise; hence the data is reloaded. So I found this answer that uses parcelables and this article on Codepath (still on parcelables). After I have followed the instructions explicitly (or so I feel), there seems to be no change: the call to get data is repeated each time the activity is recreated.

FruitItems

public class FruitItems implements Parcelable {
    private String fruit_title;
    private String fruit_description;
    private String fruit_image;

    public String getFruit_title() {
        return fruit_title;
    }

    public void setFruit_title(String fruit_title) {
        this.fruit_title = fruit_title;
    }

    public String getFruit_description() {
        return fruit_description;
    }

    public void setFruit_description(String fruit_description) {
        this.fruit_description = fruit_description;
    }

    public String getFruit_image() {
        return fruit_image;
    }

    public void setFruit_image(String fruit_image) {
        this.fruit_image = fruit_image;
    }



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

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

    public FruitItems() {
    }

    protected FruitItems(Parcel in) {
        this.fruit_title = in.readString();
        this.fruit_description = in.readString();
        this.fruit_image = in.readString();
    }

    public static final Parcelable.Creator<FruitItems> CREATOR = new Parcelable.Creator<FruitItems>() {
        @Override
        public FruitItems createFromParcel(Parcel source) {
            return new FruitItems(source);
        }

        @Override
        public FruitItems[] newArray(int size) {
            return new FruitItems[size];
        }
    };
}

MainActivity

public class MainActivity extends AppCompatActivity {

    private final String TAG = "MainActivity";
    private final String KEY_POST_ITEMS = "fruititems";

    //List of fruits
    private List<FruitItems> mFruitItemsList;

    //Views
    private RecyclerView recyclerView;
    private RecyclerView.Adapter adapter;
    private ProgressDialog mProgressDialog;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate called");

        //Initializing Views
        recyclerView = (RecyclerView) findViewById(R.id.fruit_recycler);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);



         if (savedInstanceState != null && savedInstanceState.containsKey(KEY_POST_ITEMS)) {
              mFruitItemsList = savedInstanceState.getParcelableArrayList(KEY_POST_ITEMS);

         } else {

              //Initializing the fruitlist
              mFruitItemsList = new ArrayList<>();

              if (NetworkCheck.isAvailableAndConnected(this)) {

              getData();

              } else {
            final Context mContext;
            mContext = this;
            final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
            alertDialogBuilder.setTitle(R.string.alert_titl);
            alertDialogBuilder.setCancelable(false);
            alertDialogBuilder.setIcon(R.mipmap.ic_launcher);
            alertDialogBuilder.setMessage(R.string.alert_mess);
            alertDialogBuilder.setPositiveButton(R.string.alert_retry, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    if (!NetworkCheck.isAvailableAndConnected(mContext)) {
                        alertDialogBuilder.show();
                    } else {
                        getData();
                    }

                }
            });
            alertDialogBuilder.setNegativeButton(R.string.alert_cancel, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    finish();

                }
            });
            alertDialogBuilder.show();


        }
          }

        adapter = new FruitAdapter(mFruitItemsList, this);

        recyclerView.setAdapter(adapter);

    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
           savedInstanceState.putParcelableArrayList(KEY_POST_ITEMS, ArrayList<? extends Parcelable>))mFruitItemsList);

           super.onSaveInstanceState(savedInstanceState);
    }


    //Getting json data

    private void getData(){
        Log.d(TAG, "getData called");
        //Show progress dialog
        mProgressDialog = new ProgressDialog(MainActivity.this);
        mProgressDialog.setCancelable(false);
        mProgressDialog.setMessage(this.getResources().getString(R.string.load_fruit));
        mProgressDialog.show();

        //Creating a json request
        JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(ConfigFruit.GET_URL,
                new Response.Listener<JSONArray>() {
                    @Override
                    public void onResponse(JSONArray response) {
                        Log.d(TAG, "onResponse called");
                        //Dismissing the progress dialog
                        if (mProgressDialog != null) {
                            mProgressDialog.hide();
                        }


                        //calling method to parse json array
                        parseData(response);

                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {

                    }
                });

        //Creating request queue
        RequestQueue requestQueue = Volley.newRequestQueue(this);

        //Adding request to the queue
        requestQueue.add(jsonArrayRequest);

    }

    //parsing json data
    private void parseData(JSONArray array){
        Log.d(TAG, "Parsing array");


        for(int i = 0; i<array.length(); i++) {
            FruitItems fruitItem = new FruitItems();
            JSONObject jsonObject = null;
            try {
                jsonObject = array.getJSONObject(i);
                fruitItem.setFruit_title(jsonObject.getString(ConfigFruit.TAG_POST_TITLE));
                fruitItem.setFruit_description(jsonObject.getString(ConfigFruit.TAG_POST_DESCRIPTION));

                //Parsing image
                JSONObject fruitImage = jsonObject.getJSONObject("thumbnail");
                fruitItem.setFruit_image(fruitImage.getString("url"));

            } catch (JSONException w) {
                w.printStackTrace()
            }
            mFruitItemsList.add(fruitItem);
        }

        adapter.notifyItemRangeChanged(0, adapter.getItemCount());

    }

}

I may not be a pro but I know that I have goofed somewhere in the codes above, else it should have worked.

Now, my question is where did I goof and how do I plug this mistake?

EDIT

I have edited the codes above to reflect the answer that I accepted. It works fine but there is still a problem.

I start Activity B from MainActivity. If I press the back-button in Activity B the data is saved but when I press the up-button, the getData is called again and the data is re-fetched.

Please, is there anyway around this?


Solution

  • In order to retain your data for the activity that is about to be destructed and the one that is being created, you need to override the onSaveInstance callback

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        savedInstanceState.putParcelableArrayList(KEY_POST_ITEMS, (ArrayList)mFruitItemsList);
    
        super.onSaveInstanceState(savedInstanceState);
    }
    

    NOTE: always remember to call the superclass.