Listview items are recreated in wrong order - android

I got a Listview with some String items in it. Im trying to save listview's state in fragment's onStop() method into SharedPreferences:
int i = 0;
HashSet resultsSet = new HashSet(resultAdapter.getCount());
while (i < resultAdapter.getCount()) {
resultsSet.add(resultAdapter.getItem(i)); i++;
}
editor.putStringSet("RSLTS", resultsSet);
editor.commit();
This is how I recreate Listview's state after relaunching app:
if (resultsSet != null) {
for (String result : resultsSet) { resultAdapter.insert(result, 0); }
}
As you can see, Im inserting every new line allways at first position (0) of Listview. Problem is that Listview is recreated in some weird order, for example:
Listview before saving:
3... | 2... | 1...
Listview after reloading: 2... | 1... | 3...
Cant figure it out. Why is this happening? Does anybody have some clue whats wrong with it?

You are using HashSet and according to the documentation:
This class implements the Set interface, backed by a hash table (actually a HashMap instance). 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. This class permits the null element.
So you will need to implement either TreeSet or LinkedHashSet. An arraylist is also a simple alternative.

HashSet are usually implemented with no defined order, so there is no guarantee the order will remain constant over time or when they are written to strings.
Therefore, your options are:
1) sort your String items if applicable to your case (eg alphabetical)
2) save your data to your shared pref as a concatenated string with a given separator (that you are certain doesn't appear in your data). Then, when you read back it, split the string you get from the shared pref with the given separator, to get the array of original strings.

Related

How to save data to sharedpreference in a flexible way

I save chosen items into shared preference, but as the user during runtime get to remove any of these items (from any position), and as I use the saved size (in the code below) to loop through the items, and here's the problem
Say I have 5 items ( item_1 - item_2 - item_3 - item_4 - item_5 )
if the user removed item_2 I update chosen_items_size to be 4 and I remove item_2 from the shared preference.
but when I load the items later I use the (size = which is 4 now), which as in the code below will miss item_5, how to fix this, any suggestions or better approach to achieve what I need?
mSharedPreference = getSharedPreferences("chosen_items", MODE_PRIVATE);
int size = mSharedPreference.getInt("chosen_items_size", 0);
for(int i = 1; i <= size; i++) {
mSharedPreference.getString("item_" + i, null);
}
Knowing that I want to enable drag and drop items, which using the above approach will make it pretty hard (if possible in the first place) to accomplish, any better approach to save & retrieve data / items?
Thank you
If you have a small amount of strings you can store them in one delimited string in SharedPreferences like so. You could also associate some metadata with each item and delimit that too.
You could utilize a built in SQL lite database.
Is this data that must persist between sessions? if not store it locally with a class and static variables/arrays.

How would I save an Integer array list to shared preferences

I've been trying to save an integer array list in shared preferences for a couple of days now but cannot figure out how to do it.
here's the array list i'm trying to save
////list that contains checked routes///
ArrayList<Integer> checkedRoutePosition = new ArrayList<>();
and here's how the array obtains the values within it
int listViewItemPosition = ((Activity) getContext()).getIntent().getIntExtra("listViewItemPosition",0);
checkedRoutePosition.add(listViewItemPosition);
In another activity after you click the back button a new intent is started that takes me to this activity. The intent passes in the listViewItemPosition value that I need to save to the array.
The above lines of code are in my getView method of my custom adapter for a listview. After saving them I want to compare them to position in my getView. Where the values are equal I want to set a certain image. Is this code the right way to do that?
for(int i=0; i<checkedRoutePosition.size(); i++)
if(position == checkedRoutePosition.get(i)) {
checkImageView.setImageResource(checkImageResourceId);
}
Thanks for any help!
You can't write any arrays or arraylists to shared preferences. The closest you can do is write the integers to a comma separated string, write the string, and parse it when you need to read it. This is only appropriate if the size of the array is relatively small. If its large, you need to move away from SharedPreferences to another form of storage such as a file or database.

How to know the size of ParseRelation (Parse/Android)?

Since a ParseRelation can have a huge number of row, is there a performant way to get the number of these rows?
For a big size I cannot simply query all the list and get the size.
In the Parse SDK documentation, it is not recommended to use query. countInBackground when there is more than 1000 objects.
So how can I query this size?
[EDIT] : potential issue if I increment dedicated counter for the ParseRelation:
Let's say on android I display a list of items with a button to click "addToRelation".
This button should be visible only if the relation is not already done. This means I need first to check on each item if they belong to the relation.
Then, when the user click on several buttons I call for each the backend method to add the relation and increments the counter. (This already make a lot of Parse request).
Now suppose because of some bad cache synchronization the button "addToRelation" is enabled while the relation already exist for this item.
If I call the method:
obj.add("relations",relation);
// increment the relations count by using the increment function
obj.increment("relationsCount");
obj.saveInBackground(. . .)
The method will not crash (I tested that if you add twice the same relation nothing happens)
but the counter will be incremented +1!
To avoid this I need to check twice on each item if they are not already in relation. This create too much redundant remote requests. So how to avoid this ?
Another issue may a
happen when I use saveEventuallyand the method silently fail; so if the User repeat several times the action, the counter will be incremented/decrimented several times in the local cache for the "saveEventually". If for any reason the method save succed finally the counter value will be wrong !!
what you can do is to create additional fields with the name of realtionCount (or something else according to your relation name). This field will be integer and then each time you create a new object you can increment this field using the increment option. So your code should look like the following:
// create new relation
final ParseObject relation = new ParseObject("your_relation_class_name");
relation.put("{RELATION_KEY_FIELD_NAME}","{RELATION_FIELD_VALUE}");
// add the relation to the parent object
obj.add("relations",relation);
// increment the relations count by using the increment function
obj.increment("relationsCount");
obj.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null){
// object saved!
}
}
});

Android - Storing data without a database

My application records user movement with Geofence boundaries, if the user exits the Geofence, alerts are appropriately escalated. These alert are counted and displayed in a summary at the end of the activity. However I would like to create a stats page where it displays the last week or month of activities as well as the number of alerts so that I can display these in a chart. Is there anyway to do this effectively without using a database?
I had thought of writing data to a log file and reading it but curious as to if there is a better option.
You can use SharedPreferences but it will require a lot of controls, probably more then creating a database. If you insist not to use a database, put an integer to your shared preferences saving the count of your data, also that integer will become your id. Then you can store your data with a loop depending on your data.
Here is to write your data to shared preferences
SharedPreferences mSharedPrefs = getSharedPreferences("MyStoredData",
MODE_PRIVATE);
private SharedPreferences.Editor mPrefsEditor = mSharedPrefs.edit();
int count = mSharedPrefs.getInt("storedDataCount", 0);
for(int i = 0 ; i < yourCurrentDataCount ; i++) {
mPrefsEditor.putInt("data" + count, yourData.get(i));
count++;
}
mPrefsEditor.putInt("storedDataCount", count);
And to get your data,
int count = mSharedPrefs.getInt("storedDataCount", 0);
for(int i = 0 ; i < count ; i++) {
yourData.add(mSharedPrefs.getString("data" + i, "defaultData"));
count++;
}
Edit:
I should have added some explaining. The idea is to save the count of your data to generate an id, and save the tag according to it. This code will work like this, lets say you have 5 strings. Since you don't have a MyStoredData xml, it will get created. Then since you don't have the "storedDataCount" tag, you will get 0 as a count. Your loop will iterate 5 times and in each iteration, you will add a tag to your xml like "<.data0>your first data<./data0><.data1>your second data <./data1>... After your loop is done, you will modify your storedDataCount and it will become <.storedDataCount>5<./ storedDataCount>. And the next time you use your app, your count will start from 5 so your tag will start from <.data5>. For reading, you will iterate through tags by checking "data0", "data1" and so on.
You can use java serialization if you dont want to use database.
You can also use XML/JSON for storing data.
I support already mentioned favoritism towards using a DB for this task. Nevertheless, if I were to do it via FS, I would use a transactional async library like Square's tape is.
In your case I would keep the data during a session in JSON object (structure) and persist it (in onPause()) and restore it (in onRestore()) with tape's GSON Object Converter.
Should be easy out of the box, I believe.
Tape website: http://square.github.io/tape/
Alternatively to manually persisting a file or using a 3rd party library like tape, you could always (de)serialize your JSON to SharedPreferences.

How to reatain Values of list like we do for strings and int using shared preference?

I have one listView in my app, which i is use to list the differnt strings by dynamically adding the strings to ArrayList and using that in list view. I have declared this as below
public static List<String> myList = new ArrayList<String>();
this helps me in retaining the values of list even after exiting app, but i cant be able to retain it after i force close the app or cell boots off and on. Is there any way to store this list as we do in shared preference for strings and int?
Couple of methods.
1) Store the entire list as a Single String (delimiter separated) and split it when you read it back (depends on what kind of strings, because if you have delimiters inside the string, you're screwed, although you could use some kinda encoding (Base64))
2) Store them as separate variables "Key0" is the first element, "Key1" is the second...etc You get the idea...Remember to flush the Keys each time you save though.
3) Don't use Shared Preference, instead use a private file and write the entire ArrayList Object (It's serializable.) using a ObjectOutputStream
Cheers.

Categories

Resources