Reputation: 271420
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 ArrayList
s 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?
Upvotes: 3
Views: 3544
Reputation: 7918
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)
Upvotes: 1
Reputation: 1006724
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.
Upvotes: 0