如何将 HashMap 保存到共享首选项?

如何在 Android 中将 HashMap 对象保存为 共享偏好

97937 次浏览
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();

I would not recommend writing complex objects into SharedPreference. Instead I would use ObjectOutputStream to write it to the internal memory.

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

I use Gson to convert HashMap to String and then save it to 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();
}
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;
}

You could try using JSON instead.

For saving

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
}

For getting

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

As a spin off of Vinoj John Hosan's answer, I modified the answer to allow for more generic insertions, based on the key of the data, instead of a single key like "My_map".

In my implementation, MyApp is my Application override class, and MyApp.getInstance() acts to return the 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;
}

You can use this in a dedicated on shared prefs file (source: https://developer.android.com/reference/android/content/SharedPreferences.html):

getAll

added in API level 1 Map getAll () Retrieve all values from the preferences.

Note that you must not modify the collection returned by this method, or alter any of its contents. The consistency of your stored data is not guaranteed if you do.

Returns Map Returns a map containing a list of pairs key/value representing the preferences.

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

map -> string

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

string -> map

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

The lazy way: storing each key directly in SharedPreferences

For the narrow use case when your map is only gonna have no more than a few dozen elements you can take advantage of the fact that SharedPreferences works pretty much like a map and simply store each entry under its own key:

Storing the map

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

Reading keys from the map

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

In case where you use a custom preference name (i.e. context.getSharedPreferences("myMegaMap")) you can also get all keys with prefs.getAll()

Your values can be of any type supported by SharedPreferences: String, int, long, float, boolean.

I know its a little too late but i hope this could be helpfull to any one reading..

so what i do is

1) Create HashMapand add data like:-

HashMap hashmapobj = new HashMap();
hashmapobj.put(1001, "I");
hashmapobj.put(1002, "Love");
hashmapobj.put(1003, "Java");

2) Write it to shareprefrences editor like :-

SharedPreferences sharedpreferences = getSharedPreferences(MyPREFERENCES,Context.MODE_PRIVATE);
Editor editor = sharedpreferences.edit();
editor.putStringSet("key", hashmapobj );
editor.apply(); //Note: use commit if u wan to receive response from shp

3) Reading data like :- in a new class where you want it to be read

   HashMap hashmapobj_RECIVE = new HashMap();
SharedPreferences sharedPreferences (MyPREFERENCES,Context.MODE_PRIVATE;
//reading HashMap  from sharedPreferences to new empty HashMap  object
hashmapobj_RECIVE = sharedpreferences.getStringSet("key", null);

using File Stream

fun saveMap(inputMap: Map<Any, Any>, context: Context) {
val fos: FileOutputStream = context.openFileOutput("map", Context.MODE_PRIVATE)
val os = ObjectOutputStream(fos)
os.writeObject(inputMap)
os.close()
fos.close()
}


fun loadMap(context: Context): MutableMap<Any, Any> {
return try {
val fos: FileInputStream = context.openFileInput("map")
val os = ObjectInputStream(fos)
val map: MutableMap<Any, Any> = os.readObject() as MutableMap<Any, Any>
os.close()
fos.close()
map
} catch (e: Exception) {
mutableMapOf()
}
}


fun deleteMap(context: Context): Boolean {
val file: File = context.getFileStreamPath("map")
return file.delete()
}

Usage Example:

var exampleMap: MutableMap<Any, Any> = mutableMapOf()
exampleMap["2"] = 1
saveMap(exampleMap, applicationContext) //save map


exampleMap = loadMap(applicationContext) //load map

You don't need to save HashMap to file as someone else suggested. It's very well easy to save a HashMap and to SharedPreference and load it from SharedPreference when needed. Here is how:
Assuming you have a

class T

and your hash map is:

HashMap<String, T>

which is saved after being converted to string like this:

       SharedPreferences sharedPref = getSharedPreferences(
"MyPreference", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("MyHashMap", new Gson().toJson(mUsageStatsMap));
editor.apply();

where mUsageStatsMap is defined as:

HashMap<String, T>
 

The following code will read the hash map from saved shared preference and correctly load back into mUsageStatsMap:

Gson gson = new Gson();
String json = sharedPref.getString("MyHashMap", "");
Type typeMyType = new TypeToken<HashMap<String, UsageStats>>(){}.getType();
HashMap<String, UsageStats> usageStatsMap = gson.fromJson(json, typeMyType);
mUsageStatsMap = usageStatsMap;

The key is in Type typeMyType which is used in * gson.fromJson(json, typeMyType)* call. It made it possible to load the hash map instance correctly in Java.