My App: has two activities, one to create two strings (name and message), which are saved into a hashmap, transferred into JSON and saved in a SharedPreference.
The other activity fetches this SharedPreference, transfers it into a hashmap again. Then the map is "read out" by an Iterator.
Supposed to be: My Idea is, that if I do this process several times, the iterator "reads out" all the entries to the hashmap.
Problem: However, only the last input gets displayed.
Question: Why is only the last input displayed? Am I overriding the hashmap or parts of it? And if so, how can I avoid it? Or what else am I doing wrong?
Activity 1:
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
map.put(message, name);
Gson gson = new Gson();
String hashMapString = gson.toJson(map);
SharedPreferences prefs = getSharedPreferences("SP", MODE_PRIVATE);
prefs.edit().putString("hashString", hashMapString).apply();
Activity 2:
Gson gson = new Gson();
SharedPreferences prefs = getSharedPreferences("SP", MODE_PRIVATE);
String storedHashMapString = prefs.getString("hashString", "Error");
java.lang.reflect.Type type = new TypeToken<LinkedHashMap<String, String>>(){}.getType();
LinkedHashMap<String, String> map = gson.fromJson(storedHashMapString, type);
Iterator myIterator = map.keySet().iterator();
while(myIterator.hasNext()) {
String key=(String)myIterator.next();
String value=(String)map.get(key);
Toast.makeText(getApplicationContext(), "Key: "+key+" Value: "+value, Toast.LENGTH_LONG).show();
}
while doing this
prefs.edit().putString("hashString", hashMapString).apply();
you are just saving values of newly created hashmap but old losing values which were saved previously using hashString key
Solution: fetch the old value and save it along with new values
Option one : fetch previous string , convert it to jsonobject then add the values to map
Reference : creating Hashmap from a JSON String
Option two : if you have only string key-value pair then
remove { and } from both new and old map strings then simply combine them and add { and } boundary symbols
String allValues ="{"+((prefs.getString("hashString", "")+hashMapString)
.replace("{","").replace("}",""))+"}";
then later save it
prefs.edit().putString("hashString", allValues).apply();
you are seeing the last input because putString overwrites whatever was there in the first place
https://developer.android.com/reference/android/content/SharedPreferences.Editor.html
Related
I wonder how to make a registry/database list in Java. I mean if I, for example, have a variable called "data", and then I add a new entry to that called "name" with the value "David". Then I would call something like "data.name" to get the value "David".
As seen on this picture
I've been Googling but not finding anything about it.
It sounds like you want a Map from String to String. You can use a HashMap<String,String> for that.
// Create Map using HashMap
Map<String, String> data = new HashMap<String, String>();
// Set name
data.put("name", "David");
// Get name
String name = data.get("name");
System.out.println(name);
I am developing an app that generates passwords randomly. I am adding a "save" feature so that the user can save their passwords in SharedPreferences. (which is not what you are supposed to do with your passwords)
I have an activity called PasswordActivity and in that activity I display the saved passwords.
This is how I save a password: I prompt the user to enter a name/key thingy for the password so that he/she can identify it later. And then I save the key and the password in the SharedPreferences using the following method in a utility class:
public static int savePassword (Context c, String passwordKey, String passwordValue) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences (c);
Set<String> keys = prefs.getStringSet (PASSWORD_KEYS, new HashSet<String> ());
Set<String> values = prefs.getStringSet (PASSWORD_VALUES, new HashSet<String> ());
SharedPreferences.Editor editor = prefs.edit ();
boolean duplicateKey = !keys.add (passwordKey);
boolean duplicateValue = !values.add (passwordValue);
if (duplicateKey)
return KEY_DUPLICATE;
if (duplicateValue)
return VALUE_DUPLICATE;
editor.putStringSet (PASSWORD_KEYS, keys).
putStringSet (PASSWORD_VALUES, values).apply ();
return SUCCESS;
}
And I wrote another method to get the passwords and their names. The method returns a HashMap<String, String> as you might have guessed.
public static HashMap<String, String> getPasswords (Context c) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences (c);
Set<String> keys = prefs.getStringSet (PASSWORD_KEYS, new HashSet<String> ());
Set<String> values = prefs.getStringSet (PASSWORD_VALUES, new HashSet<String> ());
ArrayList<String> keysList = new ArrayList<> ();
ArrayList<String> valuesList = new ArrayList<> ();
for (String key : keys) {
keysList.add (key);
}
for (String value : values) {
valuesList.add (value);
}
HashMap<String, String> map = new HashMap<> ();
for (int i = 0 ; i < keys.size () ; i++) {
map.put (keysList.get (i), valuesList.get (i));
}
return map;
}
I admit that the code is pretty messy. I first get the things in the two sets and turn them into ArrayLists and add the stuff in the array list to the map and return.
Phew! That was a lot of work!
Now when the user generates a password and saves it, the two sets contain the right things: (These are fake data)
keys:
key1
values:
value1
That's all good. But when I generate another password and save it, the two sets become messy:
keys:
key1
key2
values:
value2
value1
Now when I call the getPasswords method, it will return
{key1, value2}, {key2, value1}
which is incorrect. After looking at the docs, I found out that:
It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time.
which I guess is the reason that makes the incorrect results.
So I was wondering is there an alternative way to store these passwords and their names?
As you're storing multiple names & passwords, i would suggest a local SQLite database. SharedPreferences are meant for single values, not sets of values.
If you can't be bothered setting up the entire SQLiteOpenHelper and all that raw SQL code, you could take a look at some ORM helpers such as SugarOrm (i currently use this, its EXTREMELY easy to set up and use)
I would recommend a database, such as SQLCipher for Android, so the user can provide a master passphrase for the app, and all the data is stored encrypted on the device.
But, let's pretend that, in order to successfully repel an alien invasion and prevent the wholesale slaughter of countless humans, you have to implement this using SharedPreferences. After that, you will need to fly with a wise-cracking companion in a commandeered alien spacecraft and successfully upload your app into the computer systems of one of the alien mother ships (which, fortunately, happen to be running Android, as Android has remarkable market share across the galaxy).
Either:
Have each key and value be separate entries in the SharedPreferences. After all, SharedPreferences is a key-value store. Use a dedicated preference file for your keys and values (so as not to collide with anything else you might want to store), then you know that all the keys are ones from the user.
Marshal the HashMap into JSON or XML or something and save that as a string, unmarshalling it as needed.
I have a List<Map> which should be of the below syntax:
[{clientName=abcd}, {clientName=defg}]
Previously I had List<Bean> which I want to replace with List<Map>.
Here is my code:
List<Map> clientList=new ArrayList<Map>();
Map<String,String> clientNameMap = new HashMap<String,String>();
clientNameMap.put("clientName","abcd");
clientList.add(clientNameMap);
clientNameMap.put("clientName","defg");
clientList.add(clientNameMap);
What happens with this code is, I am getting [{clientName=defg}, {clientName=defg}] as the output where, clientName=abcd is replaced by the 2nd value defg. How can I get the expected result which is [{clientName=abcd}, {clientName=defg}]?
Thanks
You have to re-initialize your Map<> again before adding to List<> because you are changing previous reference for Map<> object and on same key that will change previous object also.
You code should be :
List<Map> clientList=new ArrayList<Map>();
Map<String,String> clientNameMap = new HashMap<String,String>();
clientNameMap.put("clientName","abcd");
clientList.add(clientNameMap);
clientNameMap = new HashMap<String,String>(); //Initialize it again.
clientNameMap.put("clientName","defg");
clientList.add(clientNameMap);
First read up on Map and List. When you add a Map object (or any other object) to a List object, all you're doing is adding a reference to that object in the List.
It means that if you change the Map contents after adding it to the List object, that will be reflected in the List.
In a Map, moreover, the key has to be unique.
So here you need to create a new Map object before you can add the new value and add that new Map object to the list.
See this other post for details:copying a java hashmap
Try below code, Map key should be unique so when you put value to same key n times the value is just replaced for the key, In your code you are replacing the value for same key(clientName) and adding it to list so it is printing the same value which you put in last to map.
List<Map> clientList=new ArrayList<Map>();
Map<String,String> clientNameMap = new HashMap<String,String>();
clientNameMap.put("clientName-1","abcd");
clientList.add(clientNameMap);
clientNameMap.put("clientName-2","defg");
clientList.add(clientNameMap);
I'll start with what I want to achieve
Intention
The software parses XML-Data in a for-loop. The for-loop which handles the data will go until 50 (because I'm getting 50 different results). What I did at first was, that the doInBackground-method parses the whole XML data and saves it into TextViews and displays it. But now I wanted to add a splash-screen that gets displayed as long the data loads.
The XML-File is built up like any other normal XML-file, so when I go through a for-loop the keys are always the same, but the values differ.
Approaches
What I already did was to create an multidimensional array, but unfortunately you can't use Strings as an index. That's what the Map is for. This was my approach
stringArray[i]["source"] = sourceString;
Well, then I tried it with a Map. But the problem with the map was, that when the new key came again, it would just overwrite the previous key-value pair.
So I figured out I would use a HashMap with a String Collection. I handled it like this;
First I created the HashMap
public HashMap <String, Collection<String>> hashMap = new HashMap<String, Collection<String>>();
Then I put data in the HashMap for each key.
hashMap.put("source" , new ArrayList<String>());
This is what I have done in the for-loop
hashMap.get("source").add(new String(((Node) sourceList.item(0)).getNodeValue()));
Then, when finished, the onPostExecute-method starts a new intent and passes the hashMap.
protected void onPostExecute(Void result) {
super.onPostExecute(result);
Intent i = new Intent(SplashScreen.this, MainActivity.class);
i.putExtra("hashMap", hashMap);
startActivity(i);
finish();
}
And in my MainActivity I'm doing this to get the data
Intent intent = getIntent();
HashMap<String, String> hashMap = (HashMap<String, String>)intent.getSerializableExtra("hashMap");
rankingDate = new TextView(this);
rankingDate.setText("RankingDate: " + hashMap.get("rankingDate"));
layout.addView(rankingDate);
But this results in a ClassCastException : `ArrayList cannot be cast to java.lang.String" in this line
source.setText("source: " + hashMap.get("source"));
I guess it's because hashMap.get("source") contains all values of the source data. So I tried to save all the data in a String Array. But this didn't work, but I don't know why. Eclipse tells me that Type mismatch: cannot convert from String to String[]
Any advice? I'm dying to solve this problem.
You got a typo:
HashMap<String, String> hashMap = (HashMap<String, String>)intent.getSerializableExtra("hashMap");
should be:
HashMap<String, Collection<String>> hashMap = (HashMap<String, Collection<String>>)intent.getSerializableExtra("hashMap");
#Eng.Fouad answer is correct, you have an error in the casting.
You might consider using a MultiMap rather than a map of collections:
http://guava-libraries.googlecode.com/svn/tags/release03/javadoc/com/google/common/collect/Multimap.html
Use a list of maps.
You can call list.get(index).get("source") and get the result later.
semi pseudocode:
List<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>
foreach(entry in document)
map = new HashMap<String,String>();
foreach(xml in entry)
map.put(xml,xml.value)
end
list.put(index++,map)
end
Your casting your hashmap incorrectly in your main activity.
Try this:
HashMap<String, Collection<String>> hashMap = (HashMap<String, Collection<String>>)intent.getSerializableExtra("hashMap");
Hope this helps :)
I want to store some data like key and value pair in internal storage.
so i am using HashMap to store key,value pair .but i don'get sufficient solution to store and retrieve this HashMap into sharedpreferences.
Please give me some solution.
i am put my code below:
HashMap<String, String> MapListMesasges = new HashMap<String, String>();
MapListMesasges.put(FromName, message.getBody());
preferences = mActivity.getSharedPreferences(
SharePreference_messages_history_name,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
for (Entry<String, String> entry : MapListMesasges
.entrySet()) {
editor.putString(entry.getKey(), entry.getValue());
}
editor.commit();
and retrieve data from Sharedprefernces:
preferences = mActivity.getSharedPreferences(
SharePreference_messages_history_name, Context.MODE_PRIVATE);
for (Entry<String, ?> entry : preferences.getAll().entrySet()) {
MapListMesasges.put(entry.getKey(), entry.getValue().toString());
}
i will also store hashmap in adapter and set into listview.
My main purpose is to store and retrieve data into sharedprefernces and also show data into listview.
Thanks in advance.
The easiest way to store HashMap in Preferences is just convert it to the string and store it.
On the Otherside get that string convert it in HashMap and enjoy.
To Convert String to HashMap & vice-versa check this link.
You can use json for solution.
For example:
**JSON**
{
[
"name1","message1",
"name2","message2"
]
}
Store this entire json string with some key and use same key to retrieve.
Just you need to parse/create JSON. You can use GSON lib for JSON creation/parsing
There's special thing for doing operations like you described and this is SQLite.
But if you really want to store them in SharedPreferences, you can do it.
Your solution almost work. You just need to store keys as well.
StringBuilder b = new StringBuilder();
for (Entry<String, String> entry : MapListMesasges.entrySet()) {
editor.putString(entry.getKey(), entry.getValue());
if(b.length() != 0){
b.append(",");
}
b.append(entry.getKey());
}
editor.putString("KEY_FOR_PREF_KEYS",b.toString());
And to retrieve data use this
String[] keys = preferences.getString("KEY_FOR_PREF_KEYS","").split(",");
for (int i = 0; i < keys.length; i++) {
MapListMesasges.put(keys[i], preferences.getString(keys[i]));
}