Order of items in the keySet of Bundle - android

Is the order of items in the .keySet() of a Bundle in the same order as items were inserted? I am trying to send a LinkedHashMap through a parcelable from a service to the activity.
Here is the code to insert a linkedHashMap's items into a Bundle using .putSerializable:
Bundle b = new Bundle();
Iterator<Entry<Integer, String>> _cyclesIterator = cycles.entrySet().iterator();
while (_cyclesIterator.hasNext()) {
Entry<Integer, String> _entry = _cyclesIterator.next();
Log.i(TAG,"Writing to JSON CycleID" + _entry.getKey());
b.putSerializable(_entry.getKey().toString(), _entry.getValue());
}
_dest.writeBundle(b);
I am trying to read this back when the bundle is retrieved using this:
Bundle _b = in.readBundle();
if (_b != null) {
for (String _key : _b.keySet()) {
Log.i(TAG,"Reading JSON for cycle " + _key);
_lhm.put(Integer.valueOf(_key), (String)_b.getString(_key));
}
setCycles(_lhm);
}
When items go in, the log says [1,2,3,4] but when they're read back, it is [3,2,1,4]. Is there a way to ensure the same order in both?

Maps have different approach according to their use.
HashMap - The elements will be in an unpredictable, "chaotic", order.
LinkedHashMap - The elements will be ordered by entry order or last reference order, depending on the type of LinkedHashMap.
TreeMap - The elements are ordered by key.
For getting better idea you can also check this Answer.

Maps and sets (and Bundles) carry no inherent order. You could serialize a single TreeMap<Integer, String> instead of iterating and serializing each entry, or you could iterate like you're doing but then also store one more value -- an ArrayList (also serializable) of the keys.

Related

How to sort a HashMap if both have same key?

I have a hashmap which have same value but different key.I want to sort them how this will possible?
Image of this Hashmap is below
HashMap Image
public static HashMap<String,Integer> entry = new HashMap<>();
Use TreeMap for sorting by key
Use below code for sorting by value:
private static HashMap sortByValues(HashMap map) {
List list = new LinkedList(map.entrySet());
// Defined Custom Comparator here
Collections.sort(list, new Comparator() {
public int compare(Object o1, Object o2) {
return ((Comparable) ((Map.Entry) (o1)).getValue())
.compareTo(((Map.Entry) (o2)).getValue());
}
});
// Here I am copying the sorted list in HashMap
// using LinkedHashMap to preserve the insertion order
HashMap sortedHashMap = new LinkedHashMap();
for (Iterator it = list.iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
sortedHashMap.put(entry.getKey(), entry.getValue());
}
return sortedHashMap;
}
Please check here for details.
Here some good example for sorting HashMap in Java by Keys and Values.
HashMap is not meant to keep entries in sorted order, but if you have to sort HashMap based upon keys or values, you can do that in Java. Sorting HashMap on keys is quite easy, all you need to do is to create a TreeMap by copying entries from HashMap. TreeMap is an implementation of SortedMap and keeps keys in their natural order or a custom order specified by Comparator provided while creating TreeMap. This means you can process entries of HashMap in a sorted order but you cannot pass a HashMap containing mappings in a specific order, this is just not possible because HashMap doesn't guarantee any ordering. On other hand, sorting HashMap by values is rather complex because there is no direct method to support that operation. You need to write code for that. In order to sort HashMap by values you can first create a Comparator, which can compare two entries based on values. Then get the Set of entries from Map, convert Set to List and use Collections.sort(List) method to sort your list of entries by values by passing your customized value comparator. This is similar of how you sort an ArrayList in Java. Half of the job is done by now. Now create a new LinkedHashMap and add sorted entries into that. Since LinkedHashMap guarantees insertion order of mappings, you will finally have a Map where contents are sorted by values.
Detailed information over here:
https://www.java67.com/2015/01/how-to-sort-hashmap-in-java-based-on.html

Firebase Database change node ID

How can I change the naming of the nodes of my children in the image below?
questions_stats is a List<Integer>, I'm aware that I get integers as nodes Id because this is a List. I create each of the children randomly with a number between 0 and 1000. I set this ID as part of the object and to find it I loop trough the list. What I want is to set the "0671" as the Key of the Object at the moment I create it.
How should I define my object in order to access each child with an Id that I define as a String.
Each of the questions_stats is an object.
This is my UserProfile Class definition.
public class UserProfile implements Parcelable {
private List<Integer> questions_list;
private List<QuestionsStats> questions_stats;
private String country_name, share_code, user_name;
private int token_count;
private Boolean is_guest;
public UserProfile() {
}
public UserProfile(List<Integer> questions_list, List<QuestionsStats> questions_stats, String country_name, String share_code, String user_name, int token_count, Boolean is_guest) {
this.questions_list = questions_list;
this.questions_stats = questions_stats;
this.country_name = country_name;
this.share_code = share_code;
this.user_name = user_name;
this.token_count = token_count;
this.is_guest = is_guest;
}
}
I know I can set them using the child("0159").setValue(QuestionStats) individually.
But for my purpose I need to retrieve the data of the "user" as a whole and then iterate whithin questions_stats like it is a List.
How should I define my UserProfile class in order to achieve what I want?
Anybody could give me a hint?
How can I change the node names of my children in the image below?
Answer: There is no way in which you can change the names of the nodes from your Firebase database. There is no API for doing that. What can you do instead is to attach a listener on that node and get the dataSnapshot object. Having that data, you can write it in another place using other names. You cannot simply rename them from 0 to 0000, 1 to 0001 and so on.
Perhaps I should have asked for How to "Set" the node Id instead of "Change"
What I have is an List<QuestionsStats>, but when using an List<QuestionsStats> you get indexes as Keys, What I want is to have the same List<QuestionsStats> but instead of indexes, String Keys for each of my items.
So I changed my List for a Map<String, QuestionsStats>. Now the tricky part is when parceling the Object. You can use readMap() or writeMap() to parcel as shown here in this answer by #David Wasser, but it gives a warning:
Please use writeBundle(Bundle) instead. Flattens a Map into the parcel
at the current dataPosition(), growing dataCapacity() if needed. The
Map keys must be String objects. The Map values are written using
writeValue(Object) and must follow the specification there. It is
strongly recommended to use writeBundle(Bundle) instead of this
method, since the Bundle class provides a type-safe API that allows
you to avoid mysterious type errors at the point of marshalling.
So with the help of the comments in This Question I parceled using this code, note that I'm leaving the "easy" way commented in case somebody find it useful or have any comment on that :
protected UserProfile(Parcel in) {
// in.readMap(myMap, Object.class.getClassLoader());
myMap = new HashMap<>();
String[] array = in.createStringArray();
Bundle bundle = in.readBundle(Object.class.getClassLoader());
for (String s : array) {
myMap.put(s, (Object) bundle.getParcelable(s));
}
}
#Override
public void writeToParcel(Parcel dest, int flags) {
// dest.writeMap(myMap);
Bundle bundle = new Bundle();
for (Map.Entry<String, Object> entry : myMap.entrySet()) {
bundle.putParcelable(entry.getKey(), entry.getValue());
}
Set<String> keySet = myMap.keySet();
String[] array = keySet.toArray(new String[keySet.size()]);
dest.writeStringArray(array);
dest.writeBundle(bundle);
}
Why I want this, well at the moment my list contains less than 100 items but it could grow up to a 1000, I'm no Pro, but I believe that if I already know the key of the item I'm interested in will be always better than having to iterate over the list to find it. In the end my main problem was the usage of a Map, I did not know howto.

Convert Array list to Sparse Array

I have copied some code from a project and want to reuse a small part of it in my private app.
The class contains a Sparse Array
public class GolfResult {
String hcpAfter;
String hcpBefore;
SparseArray roundResults;
public GolfResult() {
hcpAfter = "";
hcpBefore = "";
roundResults = new SparseArray();
}
}
I have created an ArrayList for roundResults that is filled with the necessary data.
Then I am trying to fill the instance with content.
GolfResult golferRes = new GolfResult();
SparseArray<RoundResults> hu= new SparseArray<>();
hu = roundresults; // *
golferRes.setHcpAfter("33");
golferRes.setHcpBefore("kk");
golferRes.setRoundResults(hu);
But the problem is that hu = roudresults is not possible, because of the error message:
required: Android.util.SparseArray found: java.util.Array List
Any help will be welcome.
After receiving two helpful answers I got a step further, but now I am facing the problem that my SparseArray hu is empty {}.
The content of hu should be the class roundresults that has the following structure:
public class RoundResults {
boolean actualRound;
private List<HoleResult> holeResults;
Integer roundId;
Integer roundNumber;
String unfinishedReason;
The arrayList roundresults has the size of 1 and has data in the objects.
unfinishedReason =""
holeResults = ArrayLIST size= 18
roundID = "1"
roundNumber = "1"
actualRound = true
hu ={}
mValues = All elements are null
mSize = 0
Does anybody have an idea why?
SparseArray is different than ArrayList, from the documentation:
SparseArrays map integers to Objects. Unlike a normal array of
Objects, there can be gaps in the indices. It is intended to be more
memory efficient than using a HashMap to map Integers to Objects, both
because it avoids auto-boxing keys and its data structure doesn't rely
on an extra entry object for each mapping.
It's using a key value pair principle where the key is an integer and the value which the key mapping is the object. You need to use put [(int key, E value)](https://developer.android.com/reference/android/util/SparseArray.html#put(int, E)) where the E is your object. Remember that:
Adds a mapping from the specified key to the specified value,
replacing the previous mapping from the specified key if there was
one.
So you need to use a loop to add each object in your ArrayList as #valentino-s says:
SparseArray<RoundResults> hu= new SparseArray<>();
for( int i = 0; i < roundresults.size(); i++) {
// i as the key for the object.
hu.put(i, roundresults.get(i));
}
If I understand well your problem, maybe you can try with this:
for ( int i=0; i<roundresults.size(); i++ ) {
hu.put(i,roundresults.get(i));
}
After some trial and error I found a solution for the empty hu:
Instead of put I used append and it is working now.
hu.append(i, roundresults.get(i));
Time for a beer.

Getting a hashmap to print out in sequence

I have retrieved data from a 2-column CSV file using HashMap. This is for use in a dictionary-style app - one column contains terms and the second contains definitions, which are linked to the terms by the HashMap.
The first thing my app does is print out the list of terms as a list. However, they seem to all come out in a random order.
I'd like them to remain in the same order that they were in in the CSV file (I won't rely on any alphabetising methods, since I have the occasional non-standard characters and would prefer to alphabetise at the source)
Here's my code, which extracts the data from the CSV file and prints it to a list:
String next[] = {}; // 'next' is used to iterate through dictionaryFile
final HashMap<String, String> dictionaryMap = new HashMap<String, String>(); // initialise a hash map for the terms
try {
CSVReader reader = new CSVReader(new InputStreamReader(getAssets().open("dictionaryFile.csv")));
while((next = reader.readNext()) != null) { // for each line of the input file
dictionaryMap.put(next[0], next[1]); // append the data to the dictionaryMap
}
} catch (IOException e) {
e.printStackTrace();
}
String[] terms = new String[dictionaryMap.keySet().size()]; // get the terms from the dictionaryMap values
terms = dictionaryMap.keySet().toArray(terms);
setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, terms));
ListView lv = getListView();
This causes the app to load, with the terms in place, but they are in a completely obscure order. How do I get them to print in the same order they originally were in?
The problem is that a normal HashMap does not guarantee the order. This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.
Try using a LinkedHashMap, it will maintain the insertion order.
From the documentation - Hash table and linked list implementation of the Map interface, with predictable iteration order
Here is a link to the docs - http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html

Android - Reading common data between Activities using a Spinner

I have an Android application which retrieves from a external server, a name and a corresponding ID (this could be 1 name and ID combo or multiple name ID combinations), these are all stored in a HashMap<String, String> - The ID as the key and the Name as the value.
What I then would like to implement is a dynamic Spinner that populates itself with the 'Names' from this HashMap and when the user selects one of these names a setting somewhere I set to the ID number. This ID number will then be used in later server requests.
My question is what is the best way to implement this custom Spinner from the HashMap so that when the option is selected the ID number is set somewhere. This ID number has to be accessible from several activities - the spinner is present in several different activities... but should have the same effect on each screen.
Design patterns and pseudo code would be hugely appreciated. At the moment the Spinner is on 2 different screens, at the top below the ActionBar, but obviously the code is in both XML layout files.
Cheers.
EDIT
Code to set names and IDs in HashMap:
// Returns a Map of blog name to blog ID associated with the authenticated user
public Map<String, String> extractBlogInfo(XMLDataExtracter blogData)
{
Log.d(TAG, "BlogOperations::extractBlogInfo()");
ArrayList<String> blogIDs = new ArrayList<String>();
ArrayList<String> blogNames = new ArrayList<String>();
Map<String, String> blogIDNamePairs = new HashMap<String, String>();
// Get ID and Names and store them in blogIDs and blogNames variables
if (blogIDs.size() == blogNames.size())
{
for(int i = 0; i < blogIDs.size(); i++)
{
blogIDNamePairs.put(blogIDs.get(i), blogNames.get(i));
}
}
else
{
// An error occured
Log.d(TAG,
"BlogOperations::extractBlogInfo() > An error occured - ID and Name array sizes do not match");
return null;
}
return blogIDNamePairs;
}
For this you can use Shared preference.. You get the Id of the selected value from spinner and stored it in shared preference..
So that you can access this value any where inside your Apps..
If you want to display the selected spinner value from Say Activity1 in Activity2 get the value from Shared preference, now it will be Id so get the corresponding Name from the Id in hash Map..
For shared preference take a look at this... and this....

Categories

Resources