如何将HashMap保存到共享偏好设置中?

108

如何将一个HashMap对象保存到Android的Shared Preferences中?


1
尝试这个:https://dev59.com/YGw05IYBdhLWcg3wmC6_#39435730 - mrtpk
13个回答

98

我使用 GsonHashMap 转换为 String 并将其保存到 SharedPrefs

private void hashmaptest()
{
    //create test hashmap
    HashMap<String, String> testHashMap = new HashMap<String, String>();
    testHashMap.put("key1", "value1");
    testHashMap.put("key2", "value2");

    //convert to string using gson
    Gson gson = new Gson();
    String hashMapString = gson.toJson(testHashMap);

    //save in shared prefs
    SharedPreferences prefs = getSharedPreferences("test", MODE_PRIVATE);
    prefs.edit().putString("hashString", hashMapString).apply();

    //get from shared prefs
    String storedHashMapString = prefs.getString("hashString", "oopsDintWork");
    java.lang.reflect.Type type = new TypeToken<HashMap<String, String>>(){}.getType();
    HashMap<String, String> testHashMap2 = gson.fromJson(storedHashMapString, type);

    //use values
    String toastString = testHashMap2.get("key1") + " | " + testHashMap2.get("key2");
    Toast.makeText(this, toastString, Toast.LENGTH_LONG).show();
}

2
如何从Gson获取HashMap?我收到了以下错误消息:com.qb.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2. - Ram
发生了“Expected BEGIN_OBJECT but was BEGIN_ARRAY”的错误,这是因为HashMap<String, String>应该是HashMap<String, Object>。如果值始终为String对象,则不会有任何问题,但如果某个键的值与String不同(例如自定义对象、列表或数组),则会抛出异常。因此,为了能够解析回所有内容,您需要使用HashMap<String, Object>。 - Stoycho Andreev

87

我不建议将复杂对象写入SharedPreference。相反,我会使用ObjectOutputStream将其写入内部存储器。

File file = new File(getDir("data", MODE_PRIVATE), "map");    
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(file));
outputStream.writeObject(map);
outputStream.flush();
outputStream.close();

6
使用ObjectInputStream。 - Kirill Rakhman
5
这是一个如何同时使用ObjectOutputStream和ObjectInputStream的示例: http://www.tutorialspoint.com/java/io/objectinputstream_readobject.htm - Krzysztof Skrzynecki
2
自从什么时候HashMap成为了一个复杂对象?你是怎么做出这个假设的? - Pedro Paulo Amorim
1
为什么您不建议将像HashMap这样的对象放入SharedPreference中? - TomV
当您写入SharedPreferences时,您保存键值数据,因此与保存哈希映射没有太大区别。 - Marina Dunst

53
private void saveMap(Map<String,Boolean> inputMap) {
    SharedPreferences pSharedPref = getApplicationContext().getSharedPreferences("MyVariables", Context.MODE_PRIVATE);
    if (pSharedPref != null){
        JSONObject jsonObject = new JSONObject(inputMap);
        String jsonString = jsonObject.toString();
        pSharedPref.edit()
            .remove("My_map")
            .putString("My_map", jsonString)
            .apply();
    }
}

private Map<String,Boolean> loadMap() {
    Map<String,Boolean> outputMap = new HashMap<>();
    SharedPreferences pSharedPref = getApplicationContext().getSharedPreferences("MyVariables", Context.MODE_PRIVATE);
    try {
        if (pSharedPref != null) {
            String jsonString = pSharedPref.getString("My_map", (new JSONObject()).toString());
            if (jsonString != null) {
                JSONObject jsonObject = new JSONObject(jsonString);
                Iterator<String> keysItr = jsonObject.keys();
                while (keysItr.hasNext()) {
                    String key = keysItr.next();
                    Boolean value = jsonObject.getBoolean(key); 
                    outputMap.put(key, value);
                }
            }
        }
    } catch (JSONException e){
        e.printStackTrace();
    }
    return outputMap;
}

完美的答案 :) - Ramkesh Yadav
我怎样从一个简单类中访问getApplicationContext - Dmitry
@Dmitry 一个快捷方式:在你的简单类中,包括设置上下文方法并将上下文设置为成员变量,然后相应地使用它。 - Vinoj John Hosan
getString() 的默认值为什么要这么奇怪而复杂?一个简单的 null 或空字符串不同样可以吗? - SMBiggs
这段代码有问题:1)你捕获了一个通用异常而不是 JSON 异常。为什么需要通用异常?因为你可能会有 NPE,但你可以通过检查 JSON 字符串的 null 值来避免这种情况(就像你已经为共享首选项做的那样)。 - elcuco
这段代码很糟糕:2)为了节省,您提交两次而不是在编辑器中应用单个操作,还将编辑器的响应链接成一个单一的逻辑命令。 - elcuco

32
Map<String, String> aMap = new HashMap<String, String>();
aMap.put("key1", "val1");
aMap.put("key2", "val2");
aMap.put("Key3", "val3");

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

for (String s : aMap.keySet()) {
    keyValuesEditor.putString(s, aMap.get(s));
}

keyValuesEditor.commit();

但是我需要将哈希映射保存为自身,就像我们将向量添加到共享首选项中一样。 - jibysthomas
如果您想要实现这个功能,那么您可能需要使用序列化并将序列化后的HashMap保存在SharedPrefs中。您可以很容易地找到如何执行此操作的代码示例。 - hovanessyan

12

基于Vinoj John Hosan的回答,我修改了答案以允许更通用的插入,基于数据的键,而不是像"My_map"那样的单个键。

在我的实现中,MyApp是我的Application覆盖类,并且MyApp.getInstance()用于返回context

public static final String USERDATA = "MyVariables";

private static void saveMap(String key, Map<String,String> inputMap){
    SharedPreferences pSharedPref = MyApp.getInstance().getSharedPreferences(USERDATA, Context.MODE_PRIVATE);
    if (pSharedPref != null){
        JSONObject jsonObject = new JSONObject(inputMap);
        String jsonString = jsonObject.toString();
        SharedPreferences.Editor editor = pSharedPref.edit();
        editor.remove(key).commit();
        editor.putString(key, jsonString);
        editor.commit();
    }
}

private static Map<String,String> loadMap(String key){
    Map<String,String> outputMap = new HashMap<String,String>();
    SharedPreferences pSharedPref = MyApp.getInstance().getSharedPreferences(USERDATA, Context.MODE_PRIVATE);
    try{
        if (pSharedPref != null){
            String jsonString = pSharedPref.getString(key, (new JSONObject()).toString());
            JSONObject jsonObject = new JSONObject(jsonString);
            Iterator<String> keysItr = jsonObject.keys();
            while(keysItr.hasNext()) {
                String k = keysItr.next();
                String v = (String) jsonObject.get(k);
                outputMap.put(k,v);
            }
        }
    }catch(Exception e){
        e.printStackTrace();
    }
    return outputMap;
}

我如何从库中访问MyApp? - Dmitry
@Dmitry,你可以像从库中访问Context实例一样获取它。查看这个stackoverflow问题:是否可能在Android Library Project中获取应用程序的上下文? - Kyle Falconer

9

map -> string

val jsonString: String  = Gson().toJson(map)
preferences.edit().putString("KEY_MAP_SAVE", jsonString).apply()

字符串 -> 映射

val jsonString: String = preferences.getString("KEY_MAP_SAVE", JSONObject().toString())
val listType = object : TypeToken<Map<String, String>>() {}.type
return Gson().fromJson(jsonString, listType)

嗨,我是Gson的新手,如何将返回值存储在变量中? - Limun

2
你可以尝试使用 JSON 来代替。对于保存:
try {
    HashMap<Integer, String> hash = new HashMap<>();
    JSONArray arr = new JSONArray();
    for(Integer index : hash.keySet()) {
        JSONObject json = new JSONObject();
        json.put("id", index);
        json.put("name", hash.get(index));
        arr.put(json);
    }
    getSharedPreferences(INSERT_YOUR_PREF).edit().putString("savedData", arr.toString()).apply();
} catch (JSONException exception) {
    // Do something with exception
}

获取方式:

try {
    String data = getSharedPreferences(INSERT_YOUR_PREF).getString("savedData");
    HashMap<Integer, String> hash = new HashMap<>();
    JSONArray arr = new JSONArray(data);
    for(int i = 0; i < arr.length(); i++) {
        JSONObject json = arr.getJSONObject(i);
        hash.put(json.getInt("id"), json.getString("name"));
    }
} catch (Exception e) {
    e.printStackTrace();
}

1
你可以在专用或共享的偏好设置文件中使用此功能(来源:https://developer.android.com/reference/android/content/SharedPreferences.html):

getAll

自API级别1添加 Map getAll() 从首选项中检索所有值。

请注意,您不得修改此方法返回的集合或更改其任何内容。如果您这样做,存储数据的一致性无法保证。

返回Map 返回包含表示首选项的键/值对列表的映射。


我认为这实际上是一个更好、更简单的想法。 你只需要为这个映射创建一个专用的SharedPreferences,除了从/到实际数据类型的额外转换之外,你就可以开始使用了。 - Henry

1

懒人法:直接将每个键存储在SharedPreferences中

对于仅包含不超过几十个元素的狭窄用例,您可以利用SharedPreferences基本上像映射一样工作的事实,并简单地将每个条目存储在自己的键下:

存储映射

Map<String, String> map = new HashMap<String, String>();
map.put("color", "red");
map.put("type", "fruit");
map.put("name", "Dinsdale");


SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
// OR use a specific pref name
// context.getSharedPreferences("myMegaMap");

for (Map.Entry<String, String> entry : map.entrySet()) {
    prefs.edit().putString(entry.getKey(), entry.getValue());
}

从地图中读取键
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
// OR use a specific pref name
// context.getSharedPreferences("myMegaMap");
prefs.getString("color", "pampa");

如果您使用自定义的首选项名称(即context.getSharedPreferences("myMegaMap")),您也可以使用prefs.getAll()获取所有键。

您的值可以是SharedPreferences支持的任何类型:Stringintlongfloatboolean


1
String converted = new Gson().toJson(map);
SharedPreferences sharedPreferences = getSharedPreferences("sharepref",Context.MODE_PRIVATE);
sharedPreferences.edit().putString("yourkey",converted).commit();

1
如何将其返回到Map中? - Sos.

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