Android SharedPreferences String Set - some items are removed after app restart - android

I save a string set in the shared preferences, if I read it out it's ok. I start other activities, go back and read it again, it's ok. If I close the application, and start it again, I get the set, but with only 1 item instead of 4. It happens all the time. Is there a known issue? What could I do wrong?
In a class, what is created in the application's oncreate method I have a SharedPreferences and a SharePreferences.Editor variable. I use them in the save and load methods.
public void saveFeedback(FeedbackItem feedbackItem) {
checkSp();
Set<String> feedbackSet = getFeedbacksSet();
if(feedbackSet == null){
feedbackSet = new HashSet<String>();
}
JSONObject json = createJSONObjectfromFeedback(feedbackItem);
feedbackSet.add(json.toString());
ed.putStringSet(CoreSetup.KEY_FEEDBACK, feedbackSet);
ed.commit();
}
public Set<String> getFeedbacksSet(){
checkSp();
Set<String> ret = sp.getStringSet(CoreSetup.KEY_FEEDBACK, null);
return ret;
}
private void checkSp(){
if(this.sp == null)
this.sp = applicationContext.getSharedPreferences(applicationContext.getPackageName(), Context.MODE_PRIVATE);
if(this.ed == null)
this.ed = this.sp.edit();
}
I just can't understand how could it happen, to store perfectly all items while the app is running, then after a restart not all items are in the set. And I think if all items are removed it could be more acceptable than some items are gone, and one item is still there. Is there an explanation?

Based on your question, you should call commit only after 4 items have been added to the set.
In your code, you are calling commit for each feedback which will overwrite the previous feedback.
Update:
http://developer.android.com/reference/android/content/SharedPreferences.html#getStringSet(java.lang.String, java.util.Set)
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.
This is exactly what you are doing

This "problem" is documented on SharedPreferences.getStringSet().
getStringSet() returns a reference of the stored HashSet object inside SharedPreferences. When you add elements to this object, they are added in fact inside SharedPreferences.
The workaround is making a copy of the returned Set and putting the new Set into SharedPreferences. I tested it and it works.
In Kotlin, that would be
val setFromSharedPreferences = sharedPreferences.getStringSet("key", mutableSetOf())
val copyOfSet = setFromSharedPreferences.toMutableSet()
copyOfSet.add(addedString)
val editor = sharedPreferences.edit()
editor.putStringSet("key", copyOfSet)
editor.apply() // or commit() if really needed

Try to create Copy of your set, and than you can save it in same prefs:
private Set<String> _setFromPrefs;
public void GetSetFromPrefs()
{
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext());
Set<String> someSets = sharedPref.getStringSet("some_sets", new HashSet<String>() );
_setFromPrefs = new HashSet<>(someSets); // THIS LINE CREATE A COPY
}
public void SaveSetsInPrefs()
{
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = sharedPref.edit();
editor.putStringSet("some_sets", _setFromPrefs);
editor.commit();
}

Ran into this same problem. Solved it by clearing the editor after instantiating and before committing.
sPrefs = PreferenceManager.getDefaultSharedPreferences(context);
sFavList = sPrefs.getStringSet(context.getResources().getString(R.string.pref_fav_key), null);
sEditor = sPrefs.edit();
sEditor.clear(); // added clear, now Set data persists as expected
if (sFavList == null) sFavList = new HashSet<>();
sFavList.add(title);
sEditor.putStringSet(context.getResources().getString(R.string.pref_fav_key), sFavList).apply();
I tried creating a copy as others suggested, but that didn't work for me.
Found this solution here.

According to the document, the String Set in SharedPreferences should treated as immutable, things go south when trying to modify it. A work around would be:
Get the existing set, make a copy of it, update the copy and then save it back to the shared preferences like it was a new set.
Set<String> feedbackSet = getFeedbacksSet();
if(feedbackSet == null){
feedbackSet = new HashSet<String>();
}
//make a copy of the set, update the copy and save the copy
Set<String> newFeedbackSet = new HashSet<String>();
JSONObject json = createJSONObjectfromFeedback(feedbackItem);
newFeedbackSet.add(json.toString());
newFeedbackSet.addAll(feedbackSet);
ed.putStringSet(CoreSetup.KEY_FEEDBACK, newFeedbackSet);
ed.commit();

public void saveFeedback(FeedbackItem feedbackItem) {
checkSp();
Set<String> feedbackSet = getFeedbacksSet();
if(feedbackSet == null){
feedbackSet = new HashSet<String>();
}
JSONObject json = createJSONObjectfromFeedback(feedbackItem);
feedbackSet.add(json.toString());
ed.putStringSet(CoreSetup.KEY_FEEDBACK, null);
ed.commit();
ed.putStringSet(CoreSetup.KEY_FEEDBACK, feedbackSet);
ed.commit();
}

To save string in sharedprefernces
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit();
editor.putString("text", mSaved.getText().toString());
editor.commit();
To retrieve data from shared preference
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
String restoredText = prefs.getString("text", null);

Related

Store json data sharedpreference and not overwrite

i create app where when user added new data , there is new label
I have tried and it worked, but I wonder how can I make the json that I store in SharedPreferences
do not over write
so I can add 2 or more user json to adapter
Here is my put string file the json variable contain user that added
SharedPreferences sharedPreferences = getSharedPreferences("newUser", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("listNewUser",json)
editor.apply();
Here is how I can get json from shared preference
try{
String listNewUserAdd = sh.getString("listNewUser","");
JSONObject object = new JSONObject(listNewUserAdd);
for (int i=0; i<object.length(); i++) {
CustomerNew customer = new CustomerNew();
customer.setCustomerName(object.getString("receiverName"));
customer.setAccountId(object.getString("customerReference"));
customer.setId(object.getLong("customerId"));
System.out.println("### GET CUSTOMER NAME "+customer.getCustomerName());
listSortNew.add(customer);
if (listSortNew == null) {
// if the array list is empty
// creating a new array list.
listSortNew = new ArrayList<>();
}
}
I think there are two ways to realize it. One way is when you put data you have to check if it exists.
SharedPreferences sharedPreferences = getSharedPreferences("newUser", MODE_PRIVATE);
String listNewUser = sharedPreferences.getString("listNewUser","");
if(!TextUtils.isEmpty(listNewUser)){
//covert it the list object
//then add the all new item to it
//finally convert it to json string
}
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("listNewUser",json)
editor.apply();
the other way is to change the SharedPreferences MODE_APPEND
but you must know, it doesn't mean that you add multiple values for each key. It means that if the file already exists it is appended to and not erased. We usually used MODE_PRIVATE
In the end I suggest you firstly get the data from it, then check if you need change, you can change the data, then save it again.

Cannot remove an object from ArrayList<Object> saved in json

I have a shopping cart where I want to remove a product there, but I'm facing an issue. I can add product to the shopping cart and I save to shared preferences, but when I want to remove it but doesn't work. Here what I did:
holder.removeProduct.setOnClickListener(v -> {
SharedPreferences preferences = mContext.getSharedPreferences(ITEMS_PREF, Context.MODE_PRIVATE);
SharedPreferences.Editor mEditor = preferences.edit();
Gson gson = new Gson();
String json = preferences.getString("artikujtShporta", "");
ArrayList<Artikujt> artikullObject = gson
.fromJson(json, new TypeToken<ArrayList<Artikujt>>(){}.getType());
if (artikullObject != null) {
artikullObject.remove(artikulli);
String jsonString = gson.toJson(artikullObject);
mEditor.putString("artikujtShporta", jsonString);
mEditor.apply();
} else {
ArrayList<Artikujt> arrayArtikuj = new ArrayList<>();
arrayArtikuj.remove(artikulli);
Type listOfTestObject = new TypeToken<ArrayList<Artikujt>>(){}.getType();
String s = gson.toJson(arrayArtikuj, listOfTestObject);
mEditor.putString("artikujtShporta", s);
mEditor.apply();
}
});
The same thing I did for adding the product, with the difference that here I call
artikullObject.remove(artikulli);
What i'm missing?
What is the problem?
The problem here will be that the instance of your class Artikujt which you want to delete from the Array is not the same as you have read out of the Preferences.
As soon as you use Gson to make your String to a new Array it will generate completely new instances of your class and obviously these will not be the same as you had before. Maybe they are equal, but they are not the same instances.
What can you do to solve this?
I am assuming that you want to have each Artikujt only once. What means you could also use a HashSet. The advantage of this is it would would use the hashCode() function to determine which instance in the set you want to remove. So you just need to override this hashCode() function in your model class and use all of its properties to calculate the hashcode. You can find a example here: https://www.sitepoint.com/how-to-implement-javas-hashcode-correctly/
Sidenote
Your else block is unnecessary. It doesn't make a lot of sense. You are creating a empty ArrayList, then you remove sth from this empty list and then you save this empty List into the shared preferences. The logic of your code wouldn't change if you would just remove this else block.

Saving an ArrayList (android)

My application is basically a quiz that presents people with world flags. I want to add a save function that adds the current flag to a separate list. Right now, this is what I do when they click the "save" button:
saveListGC.add(playList.get(1));
(playList.get(1) is the current flag). The problem is, I have to re-define the saveListGC every time the script starts, and that empties the contents:
public static ArrayList<String> saveListGC = new ArrayList<String>();
So what I'm wondering is how can I save this data, and re-load it later? I've seen things about using SharedPrefernces, but I don't really understand it. If someone could please explain it as easily as possible, I would really appreciate it. Thank you!
This a simple example of how you can use SharedPreferences:
//intiat your shared pref
SharedPreferences pref = getApplicationContext().getSharedPreferences("MyPref", 0); // 0 - for private mode
Editor editor = pref.edit();
//store data to pref
editor.putString("myString", "value 1");
editor.commit();
//retrieve data from pref
String myString = pref.getString("myString", null);
But the real problem here is that SharedPreferences can not store an Object of type List (ArrayList), but you can store an Object of type Set (like Hashset) using this method
Set<String> mySet = new HashSet<String>();
mySet.add("value1");
mySet.add("value2");
mySet.add("value3");
editor.putStringSet("MySet", mySet);
So to answer your second question, this what i propose for you to do:
//This is your List
ArrayList<String> saveListGC = new ArrayList<String>();
//Convert your List to a Set
Set<String> saveSetGC = new HashSet<String>(saveListGC);
//Now Store Data to the SharedPreferences
SharedPreferences pref = getApplicationContext().getSharedPreferences("MyPref", 0);
Editor editor = pref.edit();
editor.putStringSet("MySet", saveSetGC);
editor.commit();
//After that in another place or in another Activity , Or every where in your app you can Retreive your List back
pref = getApplicationContext().getSharedPreferences("MyPref", 0);
Set<String> mySetBack = pref.getStringSet("MySet", null);
//Convert Your Set to List again
ArrayList<String> myListBack = new ArrayList<String>(mySetBack);
//Here you can se the List as you like...............
Log.i("MyTag", myListBack.get(0));
Log.i("MyTag", myListBack.get(1));
Good Luck :)

How to avoid adding duplicate values in shared preferences in android?

In android, i am adding string values using shared preferences, but i want to compare the value which i am going to add to shared preferences with values which are already stored in shared preferences to avoid adding duplicate values, but i am not getting how to do this?
or is there any alternate method to avoid adding duplicate values in shared preferences?
I am adding string values using following code
sharedpreferences = getSharedPreferences(MyPREFERENCES, Context.MODE_PRIVATE);
Editor editor = sharedpreferences.edit();
editor.putString(Name, s);
editor.commit();
In android you cannot really have duplicate value in sharedPreference because every time you change or modify a value on sharedPreference it will replace the previous with the current. So since every instance of it has a single unique key, which mean it will always be unique (in my experience every time i messed up with this keys like giving the same name key for both an Int and boolean for example i end up crashing the app or having some kind of exception)
If im wrong i hope someone else will correct me and provide you with a better answer!
I don't know whether I'm understanding your question quite well or not, but Android's SharedPreferenceshas it's own contains to check if a a key already exists or not.
sharedpreferences = getSharedPreferences(MyPREFERENCES, Context.MODE_PRIVATE);
if (sharedpreferences.contains(NAME)) //It already contains NAME key
On the other hand, if your worries are about a single key's value not to be repeated, just read it before storing the new value and compare themselves, no more.
sharedpreferences = getSharedPreferences(MyPREFERENCES, Context.MODE_PRIVATE);
if (!sharedpreferences.getString(NAME, "").equals(s)) {
// It does not have the same value, store 's'
sharedpreferences
.edit();
.putString(NAME, s);
.commit();
}
However, in this particular case I wouldn't perform this verification, just overwrite the value and that's it, as it always gonna be the same.
First get String value from SharedPreferences as oldvalue then compare with newvalue which you want to store. If String not match then save newvalue in SharedPreferences.
Try something like this
String str_newvalue = "new string here";
SharedPreferences sharedpref = this.getSharedPreferences(this.getPackageName(), context.MODE_PRIVATE);
String str_oldvalue = sharedpref.getString("key", "");
if (!str_newvalue.equals(str_oldvalue)) {
sharedpref.edit().putString("key", str_newvalue).commit();
}
Do this
SharedPreferences prefs = getPreferences(MODE_PRIVATE);
String restoredText = prefs.getString("text", null);
if(restoredText.matches(your string))
{
// do nothing
}
else
{
//save your data
}
}

Issue with shared preference

I am using Android 2.1 sdk and I am trying to save user loggin session in to Shared preferences, the thing is after saving the value to the shared preference I am unable to retrive it. Here I am pasting the code I used to save and fetch value from SharedPrefrence.
public void setValue(String name, String value, String prefName) {
sharedPref = mContext.getSharedPreferences(prefName, Context.MODE_PRIVATE);
sharedPref.edit().putString(name, value);
sharedPref.edit().commit();
}
public String getValue(String name, String prefName) {
String value = null;
sharedPref = mContext.getSharedPreferences(prefName, Context.MODE_PRIVATE);
value = sharedPref.getString(name, value);
return value;
}
Did i miss some thing in this code, I am not retrieving any exceptions while saving and retrieving the value. Thanks for any help.
Every call to edit() returns you a new Editor instance. So you get an instance, make a change and leave it alone. Then you get a second one and commit that without changes, which results in no value changes in the preferences.
Rather chain in the commit():
sharedPref.edit().putString(name, value).commit();
Alternatively break it up into multiple lines with one specific instance:
Editor e = sharedPref.edit();
e.putString(name, value);
e.commit();
private SharedPreferences myPrefs;
myPrefs = Actionactivity.this.getSharedPreferences("myPrefs", MODE_WORLD_WRITEABLE);
SharedPreferences.Editor prefsEditor = myPrefs.edit();
prefsEditor.putString("Mobile_no", getText_no.getText().toString().trim());
prefsEditor.commit();
myPrefs = this.getSharedPreferences("myPrefs", MODE_WORLD_READABLE);
myPrefs.getString("Mobile_no", "");
try this one code work

Categories

Resources