Cannot put a Set<String> in sharedPreferences.putStringSet()? - java

Good morning! I am trying to make a toDo list and I want to do this through the sharedPreferences. The problem is that once I get the contents of the location and then add it to the contents of the list and try to push it back to sharedPreferences, I get a strange error. It does not make sense to me because the taskSet Set is defined by the items in the sharedPreferences, so how could it be the incorrect type?
public void putInSharedPreferences(View view){
Intent i = getIntent();
SharedPreferences sp = getSharedPreferences("storage", Context.MODE_PRIVATE);
Set<String> taskSet = sp.getStringSet("taskSet", new HashSet<String>());
String task = i.getStringExtra("taskText");
taskSet.add(task);
sp.edit().putStringSet(taskSet).apply();
int minutes = i.getIntExtra("chosenMinutes", 0);
}
The error I receive:
putStringSet (java.lang.String, Set) in Editor cannot be applied to (java.util.Set)
 

putSetString() takes two parameters: A key, which is aString, along with a Set<String>. So you'd put the set like this:
sp.edit().putStringSet("taskSet", taskSet).apply();
See the method definition here for more info.

Related

getting updated values from the parent activity

i am working on a project where i have to test some wifi rssi values that i am calculating in parent activity.... but for testing i have created a new activity which is launched by pressing of a button..what i want is to get the 5-6 different values from the wifi scan results and use them in test activity instead of one??
i have tried getting values in 5 different arrays and passing them to test activity but there were some complications with this method in my code.
can anybody give me some suggestions how to achieve this?
You can use a Hashmap and SharedPreferences.
1 - Set your values
Map<String, String> values = new HashMap<>();
values.put("key0", "value0");
values.put("key1", "value1");
values.put("key2", "value2");
SharedPreferences keyValues = this.getSharedPreferences("myPrefs", Context.MODE_PRIVATE);
SharedPreferences.Editor keyValuesEditor = keyValues.edit();
for (String s : values.keySet()) {
keyValuesEditor.putString(s, values.get(s));
}
keyValuesEditor.apply();
2 - Retrieve a value
SharedPreferences prefs = getSharedPreferences("myPrefs", MODE_PRIVATE);
String myValue = prefs.getString("key0", null);

firebase check if child exists

So I have my backend using firebase. What I'm aiming to do is to add user matches to a user id. However, when the user initially signs up, they have no matches. What I'm trying to do is to check whether or not the "match" child exists within a user child, if not a list child is created and the first match is stored. However, if it already exists, the match is simply added. Here's my code:
public void setMatch(final String match){
final Firebase ref = new Firebase("FIREBASEURL");
final Firebase userRef = ref.child("Flights").child(userName);
userRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
System.out.println("does the child exist? " + dataSnapshot.child("matches").exists());
if(!dataSnapshot.child("matches").exists()){
ArrayList<String> matches = new ArrayList<String>();
matches.add(match);
Firebase matchesRef = userRef.child("matches");
matchesRef.setValue(matches);
userRef.removeEventListener(this);
}else if(dataSnapshot.child("matches").exists()){
Map<String, Object> matches = new HashMap<>();
matches.put("matches", match);
userRef.child("matches").push().setValue(matches);
userRef.removeEventListener(this);
}
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
Currently, the value is being added twice (the else if is called twice if the field already exists/its called if it doesn't). I'm not sure what I'm doing wrong.
This sounds pretty overcomplicated. In the Firebase Database, it's often best to separate read and write operations as much as possible. And while push ids are a great way to store data in a chronological way; if items have a natural key, it is often better to store them under that key.
For example if your String match is really a String matchId, you can ensure that each match is present at most once by using matchId as the key.
userRef.child("matches").child(matchId).setValue(true);
This operation is idempotent: it will give the same result no matter how often you run it.
You'll note that I don't check of matches already exists: the Firebase Database automatically creates all nodes that are needed to store the value and it automatically removes all nodes that have no values under them.
It looks like you create the field if it doesn't exist in the if block, and then test to see if that field (which was just created) exists, and it now does, so it adds it again. The removeEventListener call will remove the listener, but will not stop the current code from completing.
Try:
if(!dataSnapshot.child("matches").exists()){
ArrayList<String> matches = new ArrayList<String>();
matches.add(match);
Firebase matchesRef = userRef.child("matches");
matchesRef.setValue(matches);
userRef.removeEventListener(this);
return;
}else if(dataSnapshot.child("matches").exists()){
Map<String, Object> matches = new HashMap<>();
matches.put("matches", match);
userRef.child("matches").push().setValue(matches);
userRef.removeEventListener(this);
}
Adding the return statement should quite the current call, and still disable the Listener as you intended.

How to store key value pairs in SharedPreferences?

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.

Android: store an ordered list of values between app launches

I want to store the last X values that a user input into a form. I have a list of 20 values and every time the user enters a new one, the oldest value is pushed out of the list and the newest value goes in. I want this list to persist between app launches, but sharedpreferences doesn't support an ordered set, so the results will end up jumbled every time. How can I store the list in an ordered form that I can then retrieve?
Set<String> previousValues = sharedPreferences.getStringSet(getString(R.string.LAST_VALUES), null);
You can do this in several ways:
Create a SQLite database and store them in a table
Have a unique key in the sharedpreferences and use JSON to serialize them. You don't need to use the any external library, Android includes its own JSON classes,
Have multiple keys in the SharedPreference, one for each value, and an additional, numerical, for storing the index of the last one, something like:
int index = ... // number of entries
List<String> values = ... // the values you want to store
SharedPreferences prefs = ...
SharedPreferences.Editor editor = prefs.edit();
editor.putInt("index", index);
for (int i = 0 ; i < index ; i++) {
editor.putString("value." + i, values.get(i)); // assuming your values are in a String collection called 'values'
}
Of course, this snippet should give you the general idea, you would probably only add the last one every time and not all at once. When reading, you read first the index value, and then only index number of strings.
Using SharedPreferences it's easy, after API 11 the SharedPreferences Editor accept Sets as argument, so just create a Set with size of 20 and store it in shared preferences. When retrieved use it like any other java set to store only 20 values.
Set<String> lastValues = new HashSet<String>(20);
Get shared prefs
SharedPreferences prefs = getSharedPreferences(SHARED_PREFS_FILE, Context.MODE_PRIVATE);
Set shared prefs
Editor editor = prefs.edit();
try {
editor.putString(TASKS, ObjectSerializer.serialize(lastValues));
} catch (IOException e) {
e.printStackTrace();
}
editor.commit();
Examples here and here

SharedPreference Set<String> is resetting every time activity is recreated

My code here will be simplified for readability.
Methods for getting the Set and adding a password to it:
public void addPass(String pass)
{
// Get the current list.
SharedPreferences sp = getSharedPreferences("passes", 0);
SharedPreferences.Editor editor = getSharedPreferences("passes", 0).edit();
Set<String> passes = sp.getStringSet("myStrings", new HashSet<String>());
// Add the new value.
passes.add(pass);
// Save the list.
editor.putStringSet("myStrings", passes);
editor.commit();
}
public Set<String> getPasses()
{
SharedPreferences sp = getSharedPreferences("passes", 0);
return sp.getStringSet("myStrings", new HashSet<String>());
}
Reading from the Set
Set<String> x = getPasses();
String[] passes = x.toArray(new String[0]); // convert the set to array
toast(Arrays.toString(passes)); // test what the set looks like
I converted the set to an array because it was easier to test conditions with an array for me.
Adding to the Set
EditText password1 = new EditText(this);
String p1 = password1.getText().toString();
addPass(p1.trim()); // add it to the set
toast("Account successfully created.");
Problem
When I first ran this code, I added three String values: "a", "b", "c" (in that order).
All the value were added to the Set correctly and it was confirmed with this line of code from above:
toast(Arrays.toString(passes)); // test what the set looks like
It outputted [b, c, a] after the "c" was added to the set.
The problem is that when I closed the app and reopened it, the Set only contained "a".
I could add the "b" and "c" values again, but the cycle would just continue where the Set only kept the first value added to it after the activity was recreated.
I've troubleshooted for a while and cannot fix it. I can provide more detail on how and when I'm using this code if necessary. I'm hoping I don't need to and someone can point out a problem in the code as shown.
Was searching for a solution for the same issue, a solution to this would be
// Get the current list.
SharedPreferences sp = getSharedPreferences("passes", 0);
SharedPreferences.Editor editor = getSharedPreferences("passes", 0).edit();
Set<String> passes = sp.getStringSet("myStrings", new HashSet<String>());
//Make a copy, update it and save it
Set<String> newPasses = new HashSet<String>();
newPasses.add(pass);
newPasses.addAll(passes);
editor.putStringSet("myStrings", newPasses); editor.commit();
It might be that your issue stems from using getStringSet(), have a look at the docs:
public abstract Set<String> getStringSet (String key, Set<String> defValues)
Retrieve a set of String values from the preferences.
Note that you must not modify the set instance returned by this call. The consistency of the stored data is not guaranteed if you do, nor is your ability to modify the instance at all.
Based on this doc , and this SO Post about the exact same problem as yours, it seems you should create a new copy of the returned instance of the HashSet, and you seem to have done that, at least from what code you've pasted here. Maybe there's something else that's being missed.
However, check out the answer on this post . What the guy did was:
Add the first value to SharedPreferences as a String Set.
To add subsequent values, first read the existing pref into a new String Set.
Remove the old String Set key.
Modify the new string set to add the new values you want to store.
Add the new String Set to preferences.
While that is a long and silly way to do things, it seems like the last option. So basically, store all the values you want to store, in one go (not in instalments). If you want to add new values, remove the old key, create a new key with the old + new values, then store the new key.
Hope that helps.

Categories