【问题标题】:How to save custom ArrayList on Android screen rotate?如何在 Android 屏幕旋转上保存自定义 ArrayList?
【发布时间】:2012-09-12 07:12:51
【问题描述】:

我有一个带有自定义对象的ArrayList,我希望能够在屏幕旋转时保存和恢复这些对象。

我知道这可以用onSaveInstanceStateonRestoreInstanceState 来完成,如果我要让ArrayList 成为它自己的类,它实现ParcelableSerializable... 但是有没有办法在不创建另一个类的情况下这样做吗?

【问题讨论】:

    标签: android object arraylist parcelable screen-rotation


    【解决方案1】:

    您不需要创建新类来传递自定义对象的 ArrayList。您应该为您的对象简单地实现 Parcelable 类,并在onSaveInstanceState()onRestoreInstanceState() 中使用Bundle#putParcelableArrayList()。这个方法会自己存储一个 Parcelables 的 ArrayList。


    因为 Parcelables(以及 Serializables 和 Bundles)的主题有时让我头疼,这里有一个 ArrayList 的基本示例,其中包含存储在 Bundle 中的自定义 Parcelable 对象。 (这是可剪切和粘贴运行的,无需布局。)

    实现 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];
            }
        };
    }
    

    保存/恢复状态

    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);
        }
    }
    

    【讨论】:

    • 谢谢!但是,我迷失了private MyObject(Parcel in) { color = in.readString(); number = in.readString(); } 位...这对字符串来说很容易,但是如何读取我的自定义数组列表? in.readArrayList(MyObject.class.getClassLoader()) 给我一个错误。
    • 嗯,在您的问题中,您询问了暗示ArrayList&lt;MyObject&gt; 的“带有自定义对象的ArrayList”,这个答案在Parcelable.Creator 中处理;但是您的评论只是问“我如何阅读我的自定义数组列表”,暗示MyArrayList。你想扩展什么类? (抱歉,技术性很强,但我想尽快给你最好的答案。)
    • 对不起,我的意思是 ArrayList
    • 好的,那么你不需要在你的对象类中readArrrayList()。查看我发布的示例活动中的onCreate()。我检查:如果ArrayList&lt;MyObject&gt; 尚不存在,则创建它;如果确实存在,请在 ArrayList&lt;MyObject&gt;list = savedInstanceState.getParcelableArrayList("key"); 中读取。这有意义吗?如果有帮助,我可以轻松地更详细地评论我的示例。
    • @Sam 您如何将 Parcelable 与字符串的 ArrayList 一起使用,而不是自定义对象?
    【解决方案2】:

    您可以使用onRetainNonConfigurationInstance()。它允许您在配置更改之前保存任何对象,并在之后使用getLastNonConfigurationInstanceState() 恢复它。

    活动内部:

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

    内部onCreate()

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

    处理运行时更改:http://developer.android.com/guide/topics/resources/runtime-changes.html 文档:http://developer.android.com/reference/android/app/Activity.html#onRetainNonConfigurationInstance%28%29

    【讨论】:

    • 哇,从来不知道这个功能!超级简单,正是我所需要的......但是,我看到它已被弃用......
    • 不幸的是,它仍然有效,并且没有其他简单的方法可以做到这一点。山姆的答案是我发现的唯一其他方法,但实施起来要困难得多。
    • 如果你正在使用 Fragments,你可以使用 Fragment.setRetainInstance(true) 代替,这是它的更新版本(但仅适用于 Fragments)。文档:developer.android.com/reference/android/app/…
    • 只有在不幸没有将片段添加到后台堆栈时才有效
    【解决方案3】:
    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);
    }
    

    【讨论】:

    • 欢迎来到 Stack Overflow。您能否详细说明一下此解决方案如何回答问题?
    • 这可能有效。我还没有尝试过。不过,这真是个黑客。
    【解决方案4】:

    是的,您可以将复合对象保存在共享首选项中。比方说:

    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(); 
    

    现在您可以将对象检索为:

         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);
    

    【讨论】:

    • 这样做的坏主意 - 取决于要保存的列表的大小。 SharedPreferences 是一个 XML 文件,它不是为存储大量数据集而设计的。
    猜你喜欢
    • 2016-06-12
    • 2016-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多