是否可以将数组或对象添加到 Android 上的 SharedPreferences

Posted

技术标签:

【中文标题】是否可以将数组或对象添加到 Android 上的 SharedPreferences【英文标题】:Is it possible to add an array or object to SharedPreferences on Android 【发布时间】:2011-04-22 01:24:36 【问题描述】:

我有一个 ArrayList 的对象,它们有一个名称和一个图标指针,我想将它保存在 SharedPreferences 中。我该怎么办?

注意:我不想使用数据库

【问题讨论】:

【参考方案1】:

无论 API 级别如何,请检查 String arrays and Object arrays in SharedPreferences


保存数组

public boolean saveArray(String[] array, String arrayName, Context mContext)    
    SharedPreferences prefs = mContext.getSharedPreferences("preferencename", 0);  
    SharedPreferences.Editor editor = prefs.edit();  
    editor.putInt(arrayName +"_size", array.length);  
    for(int i=0;i<array.length;i++)  
        editor.putString(arrayName + "_" + i, array[i]);  
    return editor.commit();  
 

加载阵列

public String[] loadArray(String arrayName, Context mContext)   
    SharedPreferences prefs = mContext.getSharedPreferences("preferencename", 0);  
    int size = prefs.getInt(arrayName + "_size", 0);  
    String array[] = new String[size];  
    for(int i=0;i<size;i++)  
        array[i] = prefs.getString(arrayName + "_" + i, null);  
    return array;  
  

【讨论】:

这是一个糟糕的技术。请参阅该博客上的the comments:“这种方法的问题是您会污染您的偏好。比如说,您保存一个包含 100 个条目的数组,然后将其缩小为 2。您的偏好中仍然会有 100 个条目,除非你先把它清理干净。” 清理起来很容易 谢谢,非常漂亮的代码。这是我在 SO 上最喜欢的答案之一。 :) 这是错误的做法!!!您尝试添加 100 个变量,这太可怕了!相反,您可以将此方法与 jsonarray 和 jsonbj 一起使用:***.com/a/8287418/2652368 @AmirHosseinGhasemi 这两种方法实际上都是黑客攻击。谢谢【参考方案2】:

所以来自Data Storage上的android开发者网站:

用户偏好

共享偏好并非严格用于保存“用户偏好”,例如用户选择的铃声。如果您有兴趣为您的应用程序创建用户首选项,请参阅 PreferenceActivity,它提供了一个 Activity 框架供您创建用户首选项,这些首选项将自动持久化(使用共享首选项)。

所以我认为这没关系,因为它只是持久化的键值对。

对于原始海报来说,这并不难。您只需遍历您的数组列表并添加项目。在此示例中,为了简单起见,我使用了映射,但您可以使用数组列表并适当地更改它:

// my list of names, icon locations
Map<String, String> nameIcons = new HashMap<String, String>();
nameIcons.put("Noel", "/location/to/noel/icon.png");
nameIcons.put("Bob", "another/location/to/bob/icon.png");
nameIcons.put("another name", "last/location/icon.png");

SharedPreferences keyValues = getContext().getSharedPreferences("name_icons_list", Context.MODE_PRIVATE);
SharedPreferences.Editor keyValuesEditor = keyValues.edit();

for (String s : nameIcons.keySet()) 
    // use the name as the key, and the icon as the value
    keyValuesEditor.putString(s, nameIcons.get(s));

keyValuesEditor.commit()

您将执行类似的操作来再次读取键值对。让我知道这是否有效。

更新:如果您使用 API 级别 11 或更高版本,则有一个 method 可以写出一个字符串集

【讨论】:

感谢 Noel,我在您的代码的帮助下解决了这个问题。不过请注意代码拼写错误。 ;) 工作就像一个魅力......谢谢【参考方案3】:

写作,

SharedPreferences prefs = PreferenceManager
        .getDefaultSharedPreferences(this);
JSONArray jsonArray = new JSONArray();
jsonArray.put(1);
jsonArray.put(2);
Editor editor = prefs.edit();
editor.putString("key", jsonArray.toString());
System.out.println(jsonArray.toString());
editor.commit();

阅读,

try 
    JSONArray jsonArray2 = new JSONArray(prefs.getString("key", "[]"));
    for (int i = 0; i < jsonArray2.length(); i++) 
         Log.d("your JSON Array", jsonArray2.getInt(i)+"");
    
 catch (Exception e) 
    e.printStackTrace();

其他方法:

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

在 Java 中使用 GSON:

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 中使用 GSON

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)

【讨论】:

【参考方案4】:

共享首选项在 API 级别 11 中引入了 getStringSetputStringSet 方法,但这与旧版本的 Android(仍然很流行)不兼容,并且仅限于字符串集。

Android 没有提供更好的方法,并且循环遍历地图和数组来保存和加载它们不是很容易和干净,特别是对于数组。但更好的实现并不难:

package com.example.utils;

import org.json.JSONObject;
import org.json.JSONArray;
import org.json.JSONException;

import android.content.Context;
import android.content.SharedPreferences;

public class JSONSharedPreferences 
    private static final String PREFIX = "json";

    public static void saveJSONObject(Context c, String prefName, String key, JSONObject object) 
        SharedPreferences settings = c.getSharedPreferences(prefName, 0);
        SharedPreferences.Editor editor = settings.edit();
        editor.putString(JSONSharedPreferences.PREFIX+key, object.toString());
        editor.commit();
    

    public static void saveJSONArray(Context c, String prefName, String key, JSONArray array) 
        SharedPreferences settings = c.getSharedPreferences(prefName, 0);
        SharedPreferences.Editor editor = settings.edit();
        editor.putString(JSONSharedPreferences.PREFIX+key, array.toString());
        editor.commit();
    

    public static JSONObject loadJSONObject(Context c, String prefName, String key) throws JSONException 
        SharedPreferences settings = c.getSharedPreferences(prefName, 0);
        return new JSONObject(settings.getString(JSONSharedPreferences.PREFIX+key, ""));
    

    public static JSONArray loadJSONArray(Context c, String prefName, String key) throws JSONException 
        SharedPreferences settings = c.getSharedPreferences(prefName, 0);
        return new JSONArray(settings.getString(JSONSharedPreferences.PREFIX+key, "[]"));
    

    public static void remove(Context c, String prefName, String key) 
        SharedPreferences settings = c.getSharedPreferences(prefName, 0);
        if (settings.contains(JSONSharedPreferences.PREFIX+key)) 
            SharedPreferences.Editor editor = settings.edit();
            editor.remove(JSONSharedPreferences.PREFIX+key);
            editor.commit();
        
    

现在您可以使用这五种方法将任何收藏保存在共享首选项中。使用JSONObjectJSONArray 非常容易。您可以使用JSONArray (Collection copyFrom) 公共构造函数从任何Java 集合中创建JSONArray,并使用JSONArrayget 方法来访问元素。

共享首选项没有大小限制(除了设备的存储限制),因此这些方法适用于您希望快速轻松地存储应用中的某些集合的大多数常见情况。但是这里发生的是 JSON 解析,并且 Android 中的首选项在内部存储为 XML,因此我建议在处理兆字节数据时使用其他持久性数据存储机制。

【讨论】:

如果您使用 JSON,也许可以查看 gson:code.google.com/p/google-gson——它将 java 对象与 JSON 进行转换。 这将是一个有趣的组合。【参考方案5】:

使用 Gson 谷歌库 [1] 实现复杂对象存储的简单模式

public static void setComplexObject(Context ctx, ComplexObject obj)
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(ctx);
    SharedPreferences.Editor editor = preferences.edit();
    editor.putString("COMPLEX_OBJECT",new Gson().toJson(obj)); 
    editor.commit();


public static ComplexObject getComplexObject (Context ctx)
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(ctx);
    String sobj = preferences.getString("COMPLEX_OBJECT", "");
    if(sobj.equals(""))return null;
    else return new Gson().fromJson(sobj, ComplexObject.class);

[1]http://code.google.com/p/google-gson/

【讨论】:

最好的!将此标记为答案!【参考方案6】:

我使用下面的代码将一组腰围尺寸(已在我的 array.xml 中创建)加载到我的 preferences.xml 文件中。 @array/pant_inch_size 是整个数组的 id。

 <ListPreference 
 android:title="choosepantsize"
 android:summary="Choose Pant Size"
 android:key="pantSizePref" 
 android:defaultValue="34" 
 android:entries="@array/pant_inch_size"
 android:entryValues="@array/pant_inch_size" /> 

这用数组中的选项填充了菜单。我将默认大小设置为 34,所以当菜单弹出时,他们会看到预先选择了 34 大小。

【讨论】:

您好,Keith,感谢您的回复。我需要存储订单并且我不使用偏好 ui,所以我不认为您的代码与我需要完成的内容相匹配。还是谢谢 啊!!我误解了你的问题,对此感到抱歉。对于任何其他读者,我的 XML 代码只是从我的 array.xml 文件中获取项目并将它们加载到首选项菜单中,在这种情况下,默认首选项预选为“34”。然后我使用 java 来查找这个特定偏好的标识符,即“pantSizePref”(“key”)。【参考方案7】:

简单的方法是,将其转换为 JSON 字符串,如下例所示:

Gson gson = new Gson();
String json = gson.toJson(myObj);

然后将字符串存储在共享首选项中。 一旦您需要它,只需从共享首选项中获取字符串并转换回 JSONArray 或 JSONObject(根据您的要求。)

【讨论】:

【参考方案8】:

写作:

 private <T> void storeData(String key, T data) 
    ByteArrayOutputStream serializedData = new ByteArrayOutputStream();

    try 
        ObjectOutputStream serializer = new ObjectOutputStream(serializedData);
        serializer.writeObject(data);
     catch (IOException e) 
        e.printStackTrace();
    

    SharedPreferences sharedPreferences = getSharedPreferences(TAG, 0);
    SharedPreferences.Editor edit = sharedPreferences.edit();

    edit.putString(key, Base64.encodeToString(serializedData.toByteArray(), Base64.DEFAULT));
    edit.commit();

阅读:

private <T> T getStoredData(String key) 
    SharedPreferences sharedPreferences = getSharedPreferences(TAG, 0);
    String serializedData = sharedPreferences.getString(key, null);
    T storedData = null;
    try 
        ByteArrayInputStream input = new ByteArrayInputStream(Base64.decode(serializedData, Base64.DEFAULT));
        ObjectInputStream inputStream = new ObjectInputStream(input);
        storedData = (T)inputStream.readObject();
     catch (IOException|ClassNotFoundException|java.lang.IllegalArgumentException e) 
        e.printStackTrace();
    

    return storedData;

【讨论】:

这似乎是一个合理的建议。常见的集合都实现了 Serializable,你的基本 String、Number 和 Date 都是 Serializable。唯一的缺点是性能。【参考方案9】:

这是我成功使用的共享偏好代码,参考这个link:

  public class MainActivity extends Activity 

private static final int RESULT_SETTINGS = 1;
Button button;
public String a="dd";

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

 button = (Button) findViewById(R.id.btnoptions);


setContentView(R.layout.activity_main);

  // showUserSettings();
  

@Override
public boolean onCreateOptionsMenu(Menu menu) 
getMenuInflater().inflate(R.menu.settings, menu);
return true;
 

@Override
public boolean onOptionsItemSelected(MenuItem item) 
switch (item.getItemId()) 

case R.id.menu_settings:
 Intent i = new Intent(this, UserSettingActivity.class);
 startActivityForResult(i, RESULT_SETTINGS);
 break;

 

return true;


@Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data)     
  super.onActivityResult(requestCode, resultCode, data);

 switch (requestCode) 
 case RESULT_SETTINGS:
 showUserSettings();
 break;

  

  

  private void showUserSettings() 
 SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(this);

 StringBuilder builder = new StringBuilder();

 builder.append("\n Pet: "
  + sharedPrefs.getString("prefpetname", "NULL"));

 builder.append("\n Address:"
 + sharedPrefs.getString("prefaddress","NULL" ));

 builder.append("\n Your name: "
 + sharedPrefs.getString("prefname", "NULL"));

 TextView settingsTextView = (TextView) findViewById(R.id.textUserSettings);


  settingsTextView.setText(builder.toString());


    

   

编码愉快!

【讨论】:

【参考方案10】:

您可以使用 putStringSet

这允许你在你的偏好中保存一个 HashSet,就像这样:

保存

Set<String> values;

SharedPreferences sharedPref = 
    mContext.getSharedPreferences(PREF_KEY, Context.MODE_PRIVATE);

Editor editor = sharedPref.edit();

editor.putStringSet("YOUR_KEY", values);
editor.apply();

检索

SharedPreferences sharedPref = 
    mContext.getSharedPreferences(PREF_KEY, Context.MODE_PRIVATE);

Editor editor = sharedPref.edit();

Set<String> newList = editor.getStringSet("YOUR_KEY", null);

putStringSet 只允许一个 Set,这是一个 无序 列表。

【讨论】:

【参考方案11】:

当我遇到这个问题时,我得到了序列化解决方案,你可以序列化你的字符串,但我也想出了一个技巧。

只有在你还没有阅读过序列化的时候才阅读这篇文章,否则请继续阅读我的 hack

为了按顺序存储数组项,我们可以将数组序列化为单个字符串(通过创建一个新类 ObjectSerializer (复制代码来自 – www.androiddevcourse.com/objectserializer.html ,替换除包名))

在共享首选项中输入数据:

第 38 行的其余代码 -

将下一个参数设置为这样,这样如果没有检索到数据,它将返回空数组(我们不能放空字符串,因为容器/变量是数组而不是字符串)

来我的 Hack :-

通过在每个项目之间添加一些符号将数组的内容合并为单个字符串,然后在检索时使用该符号将其拆分。因为共享首选项很容易添加和检索字符串。 如果您担心拆分,只需查找“在 java 中拆分字符串”。

[注意:如果您的数组的内容是原始类型,如字符串、int、float 等,这可以正常工作。它适用于具有自己结构的复杂数组,假设是电话簿,但是合并和拆分会变得有点复杂。 ]

PS:我是android新手,所以不知道它是否是一个好的hack,所以如果你找到更好的hack,请告诉我。

【讨论】:

以上是关于是否可以将数组或对象添加到 Android 上的 SharedPreferences的主要内容,如果未能解决你的问题,请参考以下文章

如果不存在,Mongoose 将多个对象添加到数组

如果不存在,Mongoose会将多个对象添加到数组中

是否可以修改位于 JSON 文件上的数组?

将项目添加到 image.onload() 上的数组时,Angular 2 UI 未更新

如何将本地存储中的 JSON 对象添加到 Android Studio 上的片段列表

android 怎么上传一个String数组