Android sharedpreferences into arraylist - android

I created a simple game. At the end the user's name and score is supposed to get into a highscore list. For this i would like to store these data in sharedpreferences. I saw a post and i am trying to apply it to my app but it force closes. I don't even know if this is the right thing i am doing. So i put these keypairs (player, score) into an arraylist. From there i can get the values out into a listview.
This is just an example.
SharedPreferences.Editor scoreEditor = myScores.edit();
scoreEditor.putString("PLAYER", "Thomas");
scoreEditor.putString("SCORE", "5");
scoreEditor.commit();
final ArrayList<HashMap<String,String>> LIST = new ArrayList<HashMap<String,String>>();
Map<String, ?> items = myScores.getAll();
for(String s : items.keySet()){
HashMap<String,String> hmap = new HashMap<String,String>();
hmap.put("PLAYER", s);
hmap.put("SCORE", items.get(s).toString());
LIST.add(hmap);
}
Toast.makeText(Start.this, "LIST size: "+LIST.size(), Toast.LENGTH_LONG).show();
For me it would also be okay if i store these data like this:
scoreEditor.putString("DATA", "Thomas" + "-" + "5");
and put that into ArrayList<String> LIST = new ArrayList<String>();
but i don't know how to do it.
Could you guys help me with this?
Edit: So i could go another way as Haphazard suggested. I put together this code, but i don't know if this is the way to do it. I haven't tested it yet, as sg is wrong with the sharedpreferences and i am still trying to figure it out.
SharedPreferences.Editor scoreEditor = myScores.edit();
scoreEditor.putString("DATA", "Thomas" + "-" + "5");
scoreEditor.commit();
HashSet<String> hset=new HashSet<String>();
hset.addAll((Collection<? extends String>) myScores.getAll());
ArrayList<String> LIST = new ArrayList<String>(hset);

The SharedPreferences Editor does not accept Lists but it does 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.
Please note that the Set has to be a set of Strings so you will have to stick with your "Thomas" + "-" + "5" setup.
Edit: To your new update, I was thinking more of something like
//Retrieve the values
Set<String> set = new HashSet<String>();
set = myScores.getStringSet("key", null);
//Set the values
Set<String> set = new HashSet<String>();
set.addAll(listOfExistingScores);
scoreEditor.putStringSet("key", set);
scoreEditor.commit();
That code is untested, but it should work
EDIT: If your API level is below the get/setStringSet() level then you can try this:
1) Turn your list of high scores into a delimited string. That means if you had ["Tom, 1", "Ed, 5"] you could loop through it and turn it into a String like "Tom, 1|Ed, 5". You can easily store that using setString(..).
2) When you want to read the values back, perform a getString(..) and then String.split("|") to get the original list back. Well, it returns an array but that can be converted to a list easily enough.

Related

Looping out JSON Array using ArrayList

I am trying to learn retrofit and I have made successful attempts at posting data and now I am trying to retrieve JSON array which looks as follows:
{
"result": "success",
"message": "All Questions Have Been Selected",
"question": {
"all_question_ids": ["1","2","3"]
}
}
I am using the following getter
public ArrayList getAll_question_ids(){
return all_question_ids;
}
I am retrieving using Retrofit as follows
if (resp.getResult().equals(Constants.SUCCESS)) {
SharedPreferences.Editor editor = pref.edit();
Log.d("Question_IDs", "getAllQuestionID() = " + response.body().getQuestion().getAll_question_ids() );
editor.putString(Constants.All_QUESTION_IDS,((resp.getQuestion().getAll_question_ids().toString())));
editor.apply();
}
progress.setVisibility(View.INVISIBLE);
It is here that I am stuck, as I am retrieving the array ok but I am unsure how to loop out the Array which is now stored in Shared Preferences.
When I place a toast to show me how the IDs are coming across, my toast confirms the data as [1,2,3]
The goal is to add a dynamic button and the individual ID, i.e button 1, button 2 etc every-time the loop is iterated.
I have tried the following:
String questionNumber = pref.getString(Constants.All_QUESTION_IDS, "");
for (int i =0; i < questionNumber.length(); i++) {
try {
/*Dynamically create new Button which includes the question name
*/
AppCompatButton btn_question = new AppCompatButton(getActivity());
/*LayoutParams (int width, int height,float weight)
As LayoutParams is defaulted in px, I have called a method called dpToPX to make sure
the dynamically added EditText is the same size on all devices.
*/
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(dpToPx(280), dpToPx(45), 1);
btn_question.setBackgroundColor(Color.parseColor("#3B5998"));
btn_question.setTextColor(Color.WHITE);
// btn_question.setText(String.valueOf(x));
btn_question.setText("Question "+ pref.getString(Constants.All_QUESTION_IDS,""));
btn_question.setGravity(Gravity.CENTER);
//generate unique ID for each new EditText dynamically created
View.generateViewId();
//Log.d("TEST VALUE", "Question1 generated ID = " + btn_question.generateViewId());
params.setMargins(0, dpToPx(10), 0, dpToPx(10));
btn_question.setPadding(0, 0, 0, 0);
btn_question.setLayoutParams(params);
allEds.add(btn_question);
mLayout.addView(btn_question);
} catch (Exception e) {
Log.d(TAG, "Failed to create new edit text");
}
}
However the above is adding the value as it appears in the array e.g [1,2,3] which is obviously not what I want.
I have added a photo in case my explanation isn't clear. I want a button with 1 number added to it each time the loop iterates but I am unable to figure this out.
I have looked through lots of resource but cannot find an answer that is relevant to my problem, although, if there is, I am not familiar enough to recognise a similar issue.
If someone can offer some assistance, I would appreciate it!
When you call editor.putString(Constants.All_QUESTION_IDS,((SOMETHING.toString())));, what is actually stored depends on the implementation of the toString method in the type of SOMETHING (in this case String[]). So avoid doing that. Instead, since you're already using Gson or Jackson (or others), store the question_idsas JSON:
final String jsonIds = gson.toJson (resp.getQuestion().getAll_question_ids());
editor.putString(Constants.All_QUESTION_IDS, jsonIds);
Your actual stored value no longer depends on the implementation of something that you don't control (String[].toString). It is a valid JSON array and regardless of what tool/library you use to read it back, it's valid.
Now, to read back the stored data:
final String storedJson = pref.getString(Constants.All_QUESTION_IDS, null);
if (null == storedJson) {
// TODO: No question ids found
}
final String[] ids = gson.fromJson (storedJson, String[].class);
for (int i = 0; i < ids.length; i++) {
// make your buttons
}
This is a problem of saving and then reading out a List of items (in this case, String instances).
You've chosen to save the list by calling editor.putString() with a value of getAll_question_ids().toString(). That toString() call is going to return a string representation of your list, or, in other words, a String instance with the value [1, 2, 3]. At this point, you no longer have a List proper, but a String that looks like a list.
This is all technically fine, but it means you have to take this into account when you're trying to read out that list.
You've written this to read the list back out:
String questionNumber = pref.getString(Constants.All_QUESTION_IDS, "");
Once this line executes, questionNumber will be a String instance with the value [1, 2, 3]. Again, this is fine, but now we come to the key point: we have to convert this String back into a List.
If you know for sure that the values in this list won't have commas in them, you can do it easily:
Trim the braces off the string using substring()
Create a String[] using split()
Convert your array to a list using Arrays.asList() (you could even skip this step since iterating over an array is just as easy as iterating over a list)
Put that together and you get:
String questionNumber = pref.getString(Constants.All_QUESTION_IDS, "");
questionNumber = questionNumber.substring(1, questionNumber.length() - 1);
String[] array = questionNumber.split(", ");
List list = Arrays.asList(array);
At this point, you can iterate over your array or list:
for (String value : list) {
...
btn_question.setText("Question " + value);
...
}

how a String Set can be retrieve in Android from SharedPreferences

I have a problem to getting retrieve values from sharedPreferences that stored as a String Set.
Set<String> set = new HashSet<String>();
set.add("Price: " + String.valueOf(item.getItemPrice()));
set.add("Quantity: " + String.valueOf(QuantityofItem));
set.add("Total: " + String.valueOf(BillValue));
set.add(customizeMsg);
set.add("Image: " + item.getItemImage());
editor.putStringSet(item.getItemName(), set);
my StringSet contains these 5 values and i want to retrieve that stored data and retrieve as a list view . any method how it can be perform?
i have a problem to getting retrieve values from sharedPrefrences that stored as a String Set.
Unless you commit() or apply() that editor, your data will not be saved.
i want to retrieve that stored data
Call getStringSet() on the SharedPreferences, passing in whatever key you are using (here, item.getItemName()).
retrieve as a list view
You are welcome to create an ArrayList out of the Set<String> elements, then wrap that in an ArrayAdapter, then put the ArrayAdapter into a ListView.
I want to retrieve that stored data and retrieve as a list view.
#. I guess you are trying to retrieve stored Set data as ArrayList. Use below code to retrieve Set as ArrayList :
SharedPreferences sharedPreferences = context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
// Set
Set<String> set = sharedPreferences.getStringSet(KEY_ITEM_NAME, new HashSet<String>());
// List
ArrayList<String> list = new ArrayList<String>(set);
#. If you have stored multiple Set in SharedPreferences then do the same for others. Get Set by using KEY_ITEM_NAME value as item.getItemName().
#. If you want to show it on ListView then follow the steps described by #CommonsWare

SharedPreference StringSet to Array Order Issue

Please be patient while I explain my issue:
1) I am storing my preferences via a StringSet as follows:
SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit();
// Create a new Arraylist with the details of our details
ArrayList <String> newCityFareDetails = new ArrayList<String>();
// Store various values
newCityFareDetails.add(0, String.valueOf(cloneFare.value1()));
newCityFareDetails.add(1, String.valueOf(cloneFare.value2()));
newCityFareDetails.add(2, String.valueOf(cloneFare.value3()));
newCityFareDetails.add(3, String.valueOf(cloneFare.value4()));
newCityFareDetails.add(4, cloneFare.value5());
// Only value 5 is a string, rest are all floats
// Convert to a hashstring, give it the name of our value
Set<String> set = new HashSet<String>();
set.addAll(newCityFareDetails);
editor.putStringSet(extras.getString("startCity"), set);
// And write it to storage
editor.commit();
Now, I'm trying to read it as follows:
SharedPreferences prefs = getSharedPreferences(MY_PREFS_NAME, Context.MODE_PRIVATE);
Set<String> tryCityFromPrefs = prefs.getStringSet(currentCity, null);
if (tryCityFromPrefs!=null){
// Crude code, but we convert the preferences into a String array
String[] values = tryCityFromPrefs.toArray(new String[tryCityFromPrefs.size()]);
myFare = new Fare(Float.parseFloat(values[0]), Float.parseFloat(values[1]),
Float.parseFloat(values[2]), Float.parseFloat(values[3]), values[4]);
}
Now, problem is that the myFare is not getting initialized properly because the values in the array are scrambled. i.e. the String value that was at the last position when we save is now in the 2nd position. Is this something to do with Sets to String conversion? Or am I missing something obvious?
A Set does not guarantee order. While there are specific Set implementations (e.g., LinkedHashSet) that are ordered, that's not what SharedPreferences uses.
Your options are:
Change your app to not care about the order.
Save the data in SharedPreferences some other way. In this app, for example, I use JsonReader/JsonWriter to save an ArrayList into a single String value.
Save the data in some other fashion (e.g., JSON file, SQLite database with a sequence number to maintain order).

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);

android SharedPreferences synchronous problem adding array

hi
I have a scenario like this
I made a chat program where a user can ad friends just like in yahoo messenger or hotmail messenger. If there are many friend requests coming in to one user i´m saving them dynamically
like this: (Every request(string) look like this "queryaddnewfriend:name:UUID")
String msg = intent.getStringExtra("payload");
String[] split = msg.split(":");
String name = split[1];
String UUID = split[2];
if(msg.startsWith("queryaddnewfriend")){
//queryaddnewfriend:name:UUID
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext() );
String frn = prefs.getString("friendrequest1", "");
if(frn == ""){
SharedPreferences.Editor editor = prefs.edit();
String newReq = name.concat(":");
newReq = newReq.concat(UUID); //create the name:UUID string
editor.putString("friendrequest".concat( Integer.toString(1)), newReq);
editor.commit();
}else{
for(int index = 1; index < 1000; ++index) {
String line = prefs.getString("friendrequest".concat( Integer.toString(index)), "");
if(line == ""){
Log.d(TAG,"create new *********************************************");
String newLine = name.concat(":");
newLine = newLine.concat(UUID); //create the name:UUID string
SharedPreferences.Editor editor = prefs.edit();
editor.putString("friendrequest".concat( Integer.toString(index)), newLine);
editor.commit();
break;
}
}
}
So my SharedPreferences has non, one, or many rows like this
Dynamically added (notes the "friendrequest1" incrementation )
prefs.getString("friendrequest1","queryaddnewfriend:name:UUID");
prefs.getString("friendrequest2","queryaddnewfriend:name:UUID");
prefs.getString("friendrequest3","queryaddnewfriend:name:UUID");
The friend requests are showed to the user one by one starting with friendrequest3.
The problem comes when the user accept a friend request.
I have to remove the friendrequest3 and at the same time there could be a
new friend request coming in and the code above is executed adding a new friendrequest4.
Im using C2DM so I have no control when Google cloud is executing the above code.
When i remove "friendrequest3" because user has responded ACCEPT or REJECT friend
I will do editor.remove("friendrequest3") editor.commit();
But if the above code has added "friendrequest4" my code will fail.
the complexity of this code is now quite high and i guess one can make it higher
and at the same time increasing the "bug factor"
Any thought about doing this better would be nice, thanks!
If it were me, I think I'd be using Sqlite for this, not preferences. It's much easier to manage and process rows of data, and you'll also find it's quicker. I've found that writing a series of preferences in quick succession is actually very, very slow, as writing to flash RAM can sometimes take a lot longer than you'd expect. For that reason when I write to prefs, I usually fire off a new thread to do it.
But my suggestion is.... use a database Sqlite to store the incoming messages, and put them behind a content provider.

Categories

Resources