将ArrayList保存到SharedPreferences

375

我有一个包含自定义对象的ArrayList,每个自定义对象都包含各种字符串和数字。即使用户离开活动并希望在以后的某个时间回来,我也需要保留这个数组,但是在完全关闭应用程序后,我不需要该数组可用。我通过使用SharedPreferences将许多其他对象保存在此方式中,但我无法弄清楚如何以此方式保存整个数组。这是可能的吗?也许SharedPreferences不是解决此问题的方法?是否有更简单的方法?


你可以在这里找到答案:https://dev59.com/4GUp5IYBdhLWcg3w3ad1#40237149 - Apurva Kolapkar
这是完整的示例,请访问以下网址:http://stackoverflow.com/a/41137562/4344659 - Sanjeev Sangral
如果有人正在寻找解决方案,这可能是你正在寻找的答案,其中包含Kotlin的完整使用示例。https://stackoverflow.com/a/56873719/3710341 - Sagar Chapagain
38个回答

473
在API 11之后,SharedPreferences Editor接受Sets。你可以将List转换为HashSet或类似的东西,并以此方式存储它。当你读取回来时,将其转换为ArrayList,如果需要,进行排序,然后就可以开始了。
//Retrieve the values
Set<String> set = myScores.getStringSet("key", null);

//Set the values
Set<String> set = new HashSet<String>();
set.addAll(listOfExistingScores);
scoreEditor.putStringSet("key", set);
scoreEditor.commit();

你也可以将你的 ArrayList 序列化,然后保存/读取到 SharedPreferences 中。以下是解决方案: 编辑: 好的,下面是将 ArrayList 保存为序列化对象到 SharedPreferences 然后从 SharedPreferences 中读取它的解决方案。
由于 API 只支持将字符串存储和检索到 SharedPreferences 中(在 API 11 之后,更简单了),因此我们必须将包含任务列表的 ArrayList 对象序列化和反序列化为字符串。
在 TaskManagerApplication 类的 addTask() 方法中,我们必须获取共享首选项的实例,然后使用 putString() 方法存储序列化后的 ArrayList:
public void addTask(Task t) {
  if (null == currentTasks) {
    currentTasks = new ArrayList<task>();
  }
  currentTasks.add(t);
 
  // save the task list to preference
  SharedPreferences prefs = getSharedPreferences(SHARED_PREFS_FILE, Context.MODE_PRIVATE);
  Editor editor = prefs.edit();
  try {
    editor.putString(TASKS, ObjectSerializer.serialize(currentTasks));
  } catch (IOException e) {
    e.printStackTrace();
  }
  editor.commit();
}

同样地,我们需要在onCreate()方法中从偏好设置中检索任务列表:

public void onCreate() {
  super.onCreate();
  if (null == currentTasks) {
    currentTasks = new ArrayList<task>();
  }
 
  // load tasks from preference
  SharedPreferences prefs = getSharedPreferences(SHARED_PREFS_FILE, Context.MODE_PRIVATE);
 
  try {
    currentTasks = (ArrayList<task>) ObjectSerializer.deserialize(prefs.getString(TASKS, ObjectSerializer.serialize(new ArrayList<task>())));
  } catch (IOException e) {
    e.printStackTrace();
  } catch (ClassNotFoundException e) {
    e.printStackTrace();
  }
}

您可以从Apache Pig项目的ObjectSerializer.java获取ObjectSerializer类。


23
请记住,putStringSet 是在 API 11 中添加的。现今大部分程序员的目标至少是 API 8(Froyo)。 - Cristian
2
我喜欢这种方法的想法,因为它似乎是最干净的,但我要存储的数组是一个自定义类对象,其中包含字符串、双精度和布尔值。我该如何将这3种类型都添加到集合中?我是否必须将每个单独的对象设置为它们自己的数组,然后在存储之前分别将它们添加到不同的集合中,还是有更简单的方法? - ryandlf
5
scoreEditor 是什么? - Ruchir Baronia
5
针对2016年10月之后的读者:此评论已经得到了很多点赞,你可能会像我一样使用它,但请停止并不要这样做。HashSet会丢弃重复的值,因此你的ArrayList将不同。详情请参考:https://dev59.com/S2cs5IYBdhLWcg3wVyel - seoul
6
提醒那些看到这篇回答的人:Set 是无序的,因此保存 StringSet 会丢失你在 ArrayList 中的顺序。 - David Liu
显示剩余10条评论

134

1
根据您的列表内容,在调用“tinydb.putList()”时必须指定列表的对象类型。请查看链接页面上的示例。 - kc ochibili
在TinyDB中,我应该将什么设置为上下文参数?tinydb = new TinyDB(context); - Andreas Konstantakos
@AndreasKonstantakos getApplicationContext() 是指 new TinyDB(getApplicationContext()); - kc ochibili
1
目前,putList() 已更名为 putListString()。 - Frank Eno
2
默认情况下,TinyDB将返回一个空列表,用于表示不存在的值,因此请检查返回的列表的大小;如果为0,则可以将任何默认值分配给返回的列表变量。@RAWNAKYAZDANI - kc ochibili
显示剩余8条评论

95

Array保存在SharedPreferences中:

public static boolean saveArray()
{
    SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
    SharedPreferences.Editor mEdit1 = sp.edit();
    /* sKey is an array */
    mEdit1.putInt("Status_size", sKey.size());  

    for(int i=0;i<sKey.size();i++)  
    {
        mEdit1.remove("Status_" + i);
        mEdit1.putString("Status_" + i, sKey.get(i));  
    }

    return mEdit1.commit();     
}

SharedPreferences加载Array数据

public static void loadArray(Context mContext)
{  
    SharedPreferences mSharedPreference1 =   PreferenceManager.getDefaultSharedPreferences(mContext);
    sKey.clear();
    int size = mSharedPreference1.getInt("Status_size", 0);  

    for(int i=0;i<size;i++) 
    {
     sKey.add(mSharedPreference1.getString("Status_" + i, null));
    }

}

15
这是一个非常不错的“hack”。请注意,使用此方法时,总会存在通过未使用的旧值使SharedPreferences膨胀的可能性。例如,一个列表在某次运行时可能有100个项目,然后缩减到50个。这50个旧条目将保留在首选项中。其中一种方法是设置一个MAX值并清除该值之前的任何内容。 - Iraklis
3
@Iraklis 确实如此,不过假设您只存储了这个 ArrayList 到 SharedPreferences 中,您可以使用 mEdit1.clear() 来避免这种情况。 - AlexAndro
1
我喜欢这个“hack”。但是mEdit1.clear()会清除与此目的无关的其他值吗? - Bagusflyer
2
谢谢!如果你不介意我问一下,.remove() 有必要吗?难道偏好设置不会被覆盖吗? - Script Kitty

76

正如 @nirav 所说,最佳解决方案是使用 Gson 工具类将其作为 json 文本存储在 sharedPrefernces 中。以下是示例代码:

//Retrieve the values
Gson gson = new Gson();
String jsonText = Prefs.getString("key", null);
String[] text = gson.fromJson(jsonText, String[].class);  //EDIT: gso to gson


//Set the values
Gson gson = new Gson();
List<String> textList = new ArrayList<String>(data);
String jsonText = gson.toJson(textList);
prefsEditor.putString("key", jsonText);
prefsEditor.apply();

3
非常棒的答案!我原来不知道可以这样使用Gson。第一次见到这种用法的数组表示法。谢谢! - madu
5
要将其转换回List,可以使用以下代码:List<String> textList = Arrays.asList(gson.fromJson(jsonText, String[].class)); - Vamsi Challa
1
什么是“数据”? - CuriousNewbie

70

您可以将其转换为 JSON字符串 并将该字符串存储在 SharedPreferences 中。


我在寻找将ArrayList转换为JSONArray的大量代码,但您是否有样例可以分享一下如何转换为JSONString,以便我可以将其存储在SharedPrefs中? - ryandlf
5
使用 toString() 方法 - MByD
4
那么,我该如何从SharedPrefs中取回并将其转换回ArrayList? - ryandlf
很抱歉,我现在没有安卓SDK来测试它,但你可以看一下这里:http://benjii.me/2010/04/deserializing-json-in-android-using-gson/。你应该遍历JSON数组,并对每个对象执行他们在那里做的操作,希望明天我能够发布一个完整的示例来更新我的答案。 - MByD
@MByD 12年后... - acmpo6ou

69
/**
 *     Save and get ArrayList in SharedPreference
 */

JAVA:

public void saveArrayList(ArrayList<String> list, String key){
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
    SharedPreferences.Editor editor = prefs.edit();
    Gson gson = new Gson();
    String json = gson.toJson(list);
    editor.putString(key, json);
    editor.apply();    

}

public ArrayList<String> getArrayList(String key){
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
    Gson gson = new Gson();
    String json = prefs.getString(key, null);
    Type type = new TypeToken<ArrayList<String>>() {}.getType();
    return gson.fromJson(json, type);
}
Kotlin.
fun saveArrayList(list: java.util.ArrayList<String?>?, key: String?) {
    val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity)
    val editor: Editor = prefs.edit()
    val gson = Gson()
    val json: String = gson.toJson(list)
    editor.putString(key, json)
    editor.apply()
}

fun getArrayList(key: String?): java.util.ArrayList<String?>? {
    val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity)
    val gson = Gson()
    val json: String = prefs.getString(key, null)
    val type: Type = object : TypeToken<java.util.ArrayList<String?>?>() {}.getType()
    return gson.fromJson(json, type)
}

3
好的,最佳答案 - AlexPad
1
这是最好的答案,我一直在使用它来存储其他对象。 - Irfandi D. Vendy
1
你能否将它改造一下,使其能够存储所有的模型类? - BlackBlind
1
是的,我尝试过了,非常适合将数据存储到sharedprefs中!我投了赞成票。 - Maria Cecilia Ancheta Calianga
1
什么是类型导入? - Adam Noor
展示许多导入“getArrayList”方法内部的“Type”的选项。 - mufazmi

23

大家好,我已经找到了不使用 Gson 库解决上述问题的方法。在这里,我发布源代码。

1.变量声明即

  SharedPreferences shared;
  ArrayList<String> arrPackage;

2.变量初始化,即

 shared = getSharedPreferences("App_settings", MODE_PRIVATE);
 // add values for your ArrayList any where...
 arrPackage = new ArrayList<>();

3.使用packagesharedPreferences()将值存储到sharedPreference中:

 private void packagesharedPreferences() {
   SharedPreferences.Editor editor = shared.edit();
   Set<String> set = new HashSet<String>();
   set.addAll(arrPackage);
   editor.putStringSet("DATE_LIST", set);
   editor.apply();
   Log.d("storesharedPreferences",""+set);
 }

4. 使用retriveSharedValue()获取sharedPreference的值:

 private void retriveSharedValue() {
   Set<String> set = shared.getStringSet("DATE_LIST", null);
   arrPackage.addAll(set);
   Log.d("retrivesharedPreferences",""+set);
 }

希望这对你有所帮助...


伟大的解决方案!简单而快速! - LoveAndroid
7
一旦将内容添加到集合中,这将从列表中删除所有重复的字符串。可能不是所需的功能。 - OneCricketeer
这只适用于字符串列表吗? - CoolMind
你会以这种方式失去顺序。 - Brian Reinhold

15

Android SharedPreferances允许您将原始数据类型(布尔值,浮点数,整型,长整型,字符串和自API11起可用的StringSet)保存为XML文件。

任何解决方案的关键思想都是将数据转换为其中一种原始数据类型。

我个人喜欢将我的列表转换为JSON格式,然后将其作为SharedPreferences值保存为一个字符串。

为了使用我的解决方案,您需要添加Google的Gson库。

在gradle中只需添加以下依赖项(请使用Google的最新版本):

compile 'com.google.code.gson:gson:2.6.2'

保存数据(其中HttpParam是您的对象):

List<HttpParam> httpParamList = "**get your list**"
String httpParamJSONList = new Gson().toJson(httpParamList);

SharedPreferences prefs = getSharedPreferences(**"your_prefes_key"**, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(**"your_prefes_key"**, httpParamJSONList);

editor.apply();

获取数据(其中HttpParam是您的对象):

SharedPreferences prefs = getSharedPreferences(**"your_prefes_key"**, Context.MODE_PRIVATE);
String httpParamJSONList = prefs.getString(**"your_prefes_key"**, ""); 

List<HttpParam> httpParamList =  
new Gson().fromJson(httpParamJSONList, new TypeToken<List<HttpParam>>() {
            }.getType());

谢谢。这个答案帮助我检索并保存了我的List<MyObject>。 - visrahane
谢谢。工作正常。 - Velayutham M

12

这是您的完美解决方案.. 尝试一下吧,

public void saveArrayList(ArrayList<String> list, String key){
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
    SharedPreferences.Editor editor = prefs.edit();
    Gson gson = new Gson();
    String json = gson.toJson(list);
    editor.putString(key, json);
    editor.apply();     // This line is IMPORTANT !!!
}

public ArrayList<String> getArrayList(String key){
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
    Gson gson = new Gson();
    String json = prefs.getString(key, null);
    Type type = new TypeToken<ArrayList<String>>() {}.getType();
    return gson.fromJson(json, type);
}

10
你也可以将ArrayList转换为字符串并将其保存在偏好设置中。
private String convertToString(ArrayList<String> list) {

            StringBuilder sb = new StringBuilder();
            String delim = "";
            for (String s : list)
            {
                sb.append(delim);
                sb.append(s);;
                delim = ",";
            }
            return sb.toString();
        }

private ArrayList<String> convertToArray(String string) {

            ArrayList<String> list = new ArrayList<String>(Arrays.asList(string.split(",")));
            return list;
        }

使用convertToString方法将Arraylist转换为字符串后,您可以保存它,并使用convertToArray方法检索字符串并将其转换为数组。

在API 11之后,您可以直接将set保存到SharedPreferences中!!! :)


一个集合不是一个列表。列表可以包含重复项并且可以排序。在循环中设置分隔符没有意义,应该使用常量/定义。如果分隔符包含在字符串中,这样做甚至有效吗? - The incredible Jan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接