54

I have an ArrayList with custom objects that I would like to be able to save and restore on a screen rotate.

I know that this can be done with onSaveInstanceState and onRestoreInstanceState if I were to make the ArrayList its own class, which implements either Parcelable or Serializable... But is there a way to do this without creating another class?

5 Answers 5

92

You do not need to create a new class to pass an ArrayList of your custom objects. You should simply implement the Parcelable class for your object and use Bundle#putParcelableArrayList() in onSaveInstanceState() and onRestoreInstanceState(). This method will store an ArrayList of Parcelables by itself.


Because the subject of Parcelables (and Serializables and Bundles) sometimes makes my head hurt, here is a basic example of an ArrayList containing custom Parcelable objects stored in a Bundle. (This is cut & paste runnable, no layout necessary.)

Implementing Parcelable

public class MyObject implements Parcelable {
    String color;
    String number;

    public MyObject(String number, String color) {
        this.color = color;
        this.number = number;
    }

    private MyObject(Parcel in) {
        color = in.readString();
        number = in.readString();
    }

    public int describeContents() {
        return 0;
    }

    @Override
    public String toString() {
        return number + ": " + color;
    }

    public void writeToParcel(Parcel out, int flags) {
        out.writeString(color);
        out.writeString(number);
    }

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

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

Save / Restore States

public class Example extends ListActivity {
    ArrayList<MyObject> list;

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

        if(savedInstanceState == null || !savedInstanceState.containsKey("key")) {
            String[] colors = {"black", "red", "orange", "cyan", "green", "yellow", "blue", "purple", "magenta", "white"};
            String[] numbers = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"};

            list = new ArrayList<MyObject>();
            for(int i = 0; i < numbers.length; i++) 
                list.add(new MyObject(numbers[i], colors[i]));
        }
        else {
            list = savedInstanceState.getParcelableArrayList("key");
        }

        setListAdapter(new ArrayAdapter<MyObject>(this, android.R.layout.simple_list_item_1, list));
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putParcelableArrayList("key", list);
        super.onSaveInstanceState(outState);
    }
}
Sign up to request clarification or add additional context in comments.

9 Comments

Thanks! However, I'm lost on the private MyObject(Parcel in) { color = in.readString(); number = in.readString(); } bit... That's easy for Strings, but how do I read my custom arraylist? in.readArrayList(MyObject.class.getClassLoader()) gives me an error.
Hmm, in your question you asked about "an ArrayList with custom objects" implying ArrayList<MyObject>, which this answer handles in the Parcelable.Creator; however your comment just asked "how do I read my custom arraylist" implying MyArrayList. What class are you trying to extend? (Sorry to be technical but I want to give you the best answer fastest.)
Sorry, I do mean ArrayList<MyObject>
Ok, then you don't need to readArrrayList() in your object class. Look at onCreate() in the example Activity I posted. I check: if an ArrayList<MyObject> doesn't already exist, make it; if it does exist read in the ArrayList<MyObject> with list = savedInstanceState.getParcelableArrayList("key");. Does this make sense? I can easily comment my example in more detail if it will help.
@Sam How would you use Parcelable with an ArrayList of Strings, not custom objects?
|
3

You can use onRetainNonConfigurationInstance(). It allows you to save any object before an configuration change, and restore it after with getLastNonConfigurationInstanceState().

Inside the activity:

    @Override
    public Object onRetainNonConfigurationInstance() {
        return myArrayList;
    }

Inside onCreate():

    try{
        ArrayList myArrayList = (ArrayList)getLastNonConfigurationInstance();
    } catch(NullPointerException e) {}

Handling Runtime Changes: http://developer.android.com/guide/topics/resources/runtime-changes.html Documentation: http://developer.android.com/reference/android/app/Activity.html#onRetainNonConfigurationInstance%28%29

4 Comments

Wow, never knew about that function! Super simple and exactly what I needed... However, I see that it is deprecated...
It is, unfortunately, but it still works and there's no other easy way to do this. Sam's answer is the only other way I've found, but it's a lot harder to implement.
If you're using Fragments, you can use Fragment.setRetainInstance(true) instead, which is the newer version of this (but only works with Fragments). Documentation: developer.android.com/reference/android/app/…
That only works if the fragment wasn't added to the backstack unfortunately
2
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    ArrayList<Integer> id=new ArrayList<>();
    ArrayList<String> title=new ArrayList<>();
    for(int i=0;i<arr.size();i++){
        id.add(arr.get(i).id);
        title.add(arr.get(i).title);
    }
    outState.putIntegerArrayList("id",id);
    outState.putStringArrayList("title",title);
}

2 Comments

Welcome to Stack Overflow. Can you please elaborate a little to explain how this solution answers the question?
This might work. I did not tried it yet. It is a hell of a hack though.
0

If you just want to save an ArrayList<String> Object in your code and restore the values when you rotate your phone, you can use the onSaveInstanceState and onRestoreInstanceState override the protected methods in the Override Methods section (Ctrl + O).

What you need is the putStringArrayList and getStringArrayList functions inside these methods:

ArrayList<String> yourArrayList;
//your variables...

     //your code...

     //In some method:
     yourArrayList = new ArrayList<>(); //or what you want.


     //Saving and restoring the values:
     @Override
     protected void onSaveInstanceState(@NonNull Bundle outState) {
     super.onSaveInstanceState(outState);
         outState.putStringArrayList("nameOfYourList", yourArrayList);
     }

     @Override
     protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
         super.onRestoreInstanceState(savedInstanceState);
         yourArrayList = savedInstanceState.getStringArrayList("nameOfYourList");
         //some code to display the list or what you  need...
     }

Comments

-4

Yes, you can save your composite object in shared preferences. Let's say:

Student mStudentObject = new Student();
     SharedPreferences appSharedPrefs = PreferenceManager
      .getDefaultSharedPreferences(this.getApplicationContext());
      Editor prefsEditor = appSharedPrefs.edit();
      Gson gson = new Gson();
      String json = gson.toJson(mStudentObject);
      prefsEditor.putString("MyObject", json);
      prefsEditor.commit(); 

and now you can retrieve your object as:

     SharedPreferences appSharedPrefs = PreferenceManager
     .getDefaultSharedPreferences(this.getApplicationContext());
     Editor prefsEditor = appSharedPrefs.edit();
     Gson gson = new Gson();
     String json = appSharedPrefs.getString("MyObject", "");
     Student mStudentObject = gson.fromJson(json, Student.class);

1 Comment

Bad idea to do this - depending on the size of the list being saved. SharedPreferences is an XML file, it's not designed for storage of huge data sets.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.