how to control the arrangement of the data in sharedPreferences - android

I will try to do my best to explain the problem and thanks
im using sharedpreferences to save my data as string and to add new data i add it in an array and
the sharedprefrences file (tab is an arrayString)
tab.add(textToShow)
customadapter.notifyDataSetChanged()
editor.putString(textToShow , textToShow) // Ex : key = "hello" , value = "hello"
editor.apply()
but when i get my data when i open the app, the data in sharedpreferences file are note save with the order of the insert ( i insert at the end but it will be in order).
So i need to know how to save my data always at the end without order
this is how i get my data
mysharedpreferences = getSharedPreferences(fileName , 0 ) // 0 = MODE_PRIVATE
val editor : SharedPreferences.Editor = mysharedpreferences.edit()
/** fin 1**/
/** 2) get all data from the file and put it in mymap **/
val mymap : Map<String , *> = mysharedpreferences.all
/** fin 2**/
/** 3) initialise the table and show data **/
for ( (key , value) in mymap ) {
tab.add(value.toString())
customadapter.notifyDataSetChanged()
thelistv.adapter = customadapter
}

That's not how Maps work. A Map class is unordered, by design. There is no promise that the data comes out in the order it goes in. If that's what you need, anything that stores data in a Map in memory will not work. That includes SharedPreferences. Instead, you need to serialize it to a file yourself.

Related

Android SharedPrefences multiple values for one key

I have a probleme here.
I don't know how to read all values of a SharedPreferences for one particular key.
Actually I'm trying to write an Arraylist in preferences , then read it.
Let me explain with some code, Here is my methods for write in preferences :
fun writeArrayOnPreferences(key: String?, array: ArrayList<String>, c:Context) {
val preferences = c.getSharedPreferences(
c.getString(key), Context.MODE_PRIVATE)
with(preferences.edit()) {
for (value in array) {
putString(key, value)
}
commit()
}
}
My writing code works , it's persistent , but I don't really understand how to READ this Arraylist from preferences.
I tried a lot of things to read this but it show me only the last element wrote in preferences
I really want you to understand that I want multiple values for a specific key
This is a quick example based on Nabin Bhandari's answer
fun writeArrayOnPreferences(key: String, array: ArrayList<String>, c:Context) {
val jsonString = Gson().toJson(array)
pref.edit().putString(key, jsonString).commit()
}
fun readArrayFromPreferences(key: String, c: Context): ArrayList<String> {
val jsonString = pref.getString(key)
val array = Gson().fromJson(jsonString, ArrayList<String>()::class.java)
return array
}
ok here how it is! If you want multiple data against one key in share pref editor then SET is your solution as After API 11 the SharedPreferences Editor accept Sets. You could convert your List into a HashSet or something similar and store it like that When your read it back, convert it into an ArrayList, sort it if needed and you're good to go.
//Set the values
val yourSet = HashSet<String>()
set.addAll(listOfExistingScores)
yourPrefEditor.putStringSet("key", yourSet)
yourPrefEditor.commit()
//Retrieve the values
val yourSet = yourPref.getStringSet("key", null)
SOLUTION NUMBER 2
would be like serializing the ArrayList and passing it! but there can be a catch if any value in your array does posses any rule that can't be Parced it will crash!
For More check this Thread this is in java but it will help tell you more!
You cannot simply loop values in an ArrayList put them in the preferences using same key for all values and expect to retrieve the ArrayList back.
You can convert the 'ArrayList' in JSON format and store it in SharedPreferences. Then to parse the JSON string to get the ArrayList.
You can make this process easier with the help of a library called Gson.
Try this:
with(preferences.edit()) {
var s = ""
for (value in array) {
s = s + value + ","
}
putString(key, value)
commit()
}
your array will be saved like comma separated values which when read back in a string, by using the split function will become an array.

Shared Preferences loading multiple values

I currently am saving usernames and passwords in different shared preferences files. I want to load every value saved in the XML file, not just the first. How would this be written?
One way you could do it is the following:
//if you are running the code inside from an Activity
Context context = this;
SharedPreferences userSharedPrefs = context.getSharedPreferences("USER_NAME_PREFS", MODE_PRIVATE);
SharedPreferences pwdSharedPrefs = context.getSharedPreferences("PWD_PREFS", MODE_PRIVATE);
The method getAll() will return a data structure called HashMap which works like a dictionary:
For each value stored there is a unique key.
sidenote: By getting them all at once you are kinda breaking the purpose of this data structure but let's continue
Map<String, String> userNameHashMap = (Map<String, String>)userSharedPrefs.getAll();
Map<String, String> pwdHashMap = (Map<String, String>)pwdSharedPrefs.getAll();
then you can do whatever you want with them
want them in a list? (I am assuming your user names are strings by the way)
List<String> userNameList = new LinkedList<>();
userNameList.addAll(userNameHashMap.values());
want to know if there's a password for user john?
boolean johnHasPasswd = pwdHashMap.containsKey("john");
String johnsPass;
if(johnHasPasswd)
johnsPass = pwdHashMap.get("john");

Need to get all sharedPreferences but in correct order of insertion

I need some help in getting all sharedPreferences (keys & values) from my custom preference, but in order that they were originally inserted in the preference file. I currently have the below code but the problem is because getAll() returns a map the order changes.
public List<String> getPrefValues(String pref, Context context) {
Map<String, ?> allEntries = context.getSharedPreferences(pref,
Context.MODE_PRIVATE).getAll();
List<String> command = new ArrayList<String>();
for (Map.Entry<String, ?> entry : allEntries.entrySet()) {
command.add(new StringBuilder(entry.getKey())
.append(":")
.append(entry.getValue()).toString());
}
if (command.isEmpty()) {
return null;
} else {
return command;
}
}
You can store your desired attributes in a LinkedHashSet, because there,
The iteration order is the order in which entries were inserted
Sets are stored in preferences with:
Set<String> mySet = new LinkedHashSet();
insertAttributes(mySet);
SharedPreferences myprefs = getPrefs();
myprefs.edit().putStringSet("myKey", mySet).commit();
This is also applicable to a map structure: simply create one set, that contains all keys, and one, that contains the values.
There is NO facility in SharedPreferences for tracking insertion time. It would be better if you can figure another way (external to SP) to track this value.
Bottom line, there is no way within the current SP structure to understand 'insertion time'.
You can use the prefix as numbers for the keys when you put in the order you want to get them out.
For example: 00data, 01foo, 02cree.
Then put the Set<String> returned from getStringSet in an Array<Set> and sort it -
Set<String> set = prefs.getStringSet(key, new HashSet<String>());
Array<String> a = set.toArray();
java.util.Arrays.sort(a);

How to save variables with SharedPreferences

I have my own Objects which I need to store for later use. The User saves this object, it is turned into a JSON String, then when the User is connected to a network, the JSON String is turned back into the object operations are performed on it.
My problem is that, at run time, how do I know how to store the object?
i.e
Gson gson= new Gson();
String pointOfInterest = gson.toJson(point);
SharedPreferences.Editor sharedprefEditor = application_shared_preferences.edit();
sharedprefEditor.putString(?KEY?,pointOfInterest);
What can I use for the value of KEY? If I use an index, it will get reset every time I open or close the app, and this will replace my Objects.
Edit
Sorry I didn't make this clear enough, the method that the above code is in can be run an arbitrary number of times and there could be several pointsOfInterest to store.
First of all, if you use an index, the Preference will stay forever:
For instance:
sharedprefEditor.putString("JSON569",pointOfInterest);
You can also save the index in an other preference; for instance separated by a column:
sharedprefEditor.putString("indexes","569;789;852");
You can, easily check if an instance exists:
myPreference.getString("JSON789","").contentEquals("");
Or get all your instances:
for (int anIndex:indexes)
    Log.i("TAG","Current value: "+myPreference.getString("JSON"+anIndex,""));
Please xplain a little bit more your question, I see no difficulties there/
You can name the key whatever you want, just make it consistent. One way to do it is make a constant in your class for it:
public class MyClass {
private static final String OBJECT_KEY = "myObjectKey";
...
Then when you save your object:
Gson gson= new Gson();
String pointOfInterest = gson.toJson(point);
SharedPreferences.Editor sharedprefEditor = application_shared_preferences.edit();
sharedprefEditor.putString(OBJECT_KEY,pointOfInterest);
When you load it, just use OBJECT_KEY to get a string out of the shared preferences:
String objectString = sharedPrefs.getString( OBJECT_KEY, "" );

Using Shared Preferences with arrays

EDIT:
OK It turns out this code was working (more or less) I'd left in a line that reset the booleans I was trying to change. Thanks everyone for the help though.
Having trouble using SharedPreferences to read in saved array data when my app starts.
My _dPad Boolean and my _FreePlay Integer loads, saves and passes to and from my _renderer without any problems.
The trouble starts when I try and use some arrays
easteregg[] only has 2 entries right now so obviously I could just just turn them into separate variables but I wish to add more arras of longer length so this makes a convenient test example.
I've noted on the code what appears to happen (the easteregg[] settings just doesn't appear to have changed)
to read data:
// Read saved preferences
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
_renderer._dPad = prefs.getBoolean("_dPad", false); // * works ok *
_renderer._FreePlay = prefs.getInt("_FreePlay", 1); // * works ok *
_renderer.easteregg[0] = prefs.getBoolean("easteregg[0]", false ); // * not working
_renderer.easteregg[1] = true; // * even this is not working
setRenderer(_renderer);
to write data:
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
// As good a time as any to save current config
save = false ; // don't commit if nothing changed.
SharedPreferences prefs =
PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = prefs.edit();
if (_renderer._dPad != prefs.getBoolean("_dPad",false)){ save = true ;
editor.putBoolean("_dPad", _renderer._dPad);}
if (_renderer._FreePlay != prefs.getInt("_FreePlay",1)){ save = true ;
editor.putInt("_FreePlay", _renderer._FreePlay);}
editor.putBoolean("easteregg[0]", _renderer.easteregg[0]);
editor.putBoolean("easteregg[1]", _renderer.easteregg[1]);
if (save == true){editor.commit();}
}
And in the .renderer class
// START SAVE DATA
public boolean _dPad ; // false no Virtual Pad *Works Fine*
public int _FreePlay ; // 1 = no free play *Works Fine*
public boolean[] easteregg = new boolean[2]; *Values don't load or save*
//public boolean easteregg[]; // tried this first *CAUSES CRASH*
// END SAVE DATA
Do I have to convert the arrays to strings? I don't get how to change them.
I put your code into a quick activity, creating just the shell of the renderer class as you have above and found that your save boolean is false, so it never commits the preferences.
I forced the save to true, and played around with it and everything worked fine from there.
I'd recommend adding checks to the easter eggs the same as you have for any other preference; test to see if the current value is the same as the saved value, and if not, set the save flag.
I would suggest saving the array as a string in a single variable. It appears you have an array of booleans. So loop through it to make it a series of either ints (0, 1) or the string "true" or "false" then save it to an int or string.
I suspect the probelm might be that your setting name contains square brackets. I think that in key value names, the key name must be a valid variable name. And square brackets are not allowed in variable names.
However i would also expect this to throw an error. Does the code work if you name you settings "easteregg_01" and "easteregg_02"?
The best solutions would be to convert your array into JSON string and store it as preference value. If you have small amount of data, you can as well stick with org.json classes provided by android. If you have more data, GSON pull parser would be better, as it utlizes pull parser. And if you are really lazy, you grab my small databinding library and do:
String jsonState = preferences.getString(GAME_STATE, null);
StateStorage storage = JSONUnmarshaller.unmarshall(new JsonReader(new
StringReader(jsonState)), StateStorage.class);
and it will instantiate java class for you and fill in the data. And to save:
SharedPreferences.Editor editor = getPreferences(MODE_PRIVATE).edit();
StringWriter writer = new StringWriter();
JsonWriter jsonWriter = new JsonWriter(writer);
JSONMarshaller.marshall(jsonWriter, ss);
editor.putString(GAME_STATE, writer.toString());
editor.commit();
Databinding library is available on github, or from maven central:
https://github.com/ko5tik/jsonserializer
PS: at the moment I work on injection of preference values ( at the moment primitives only):
https://github.com/ko5tik/andject

Categories

Resources