Every 3 seconds, I am receiving text messages containing latitude and longitude. To send the coordinates from my SmsReceiver.class to my MapActivity.class, I used intent, which causes my Google Map to refresh every time I receive the coordinates. Every time I receive a message, it intents another MapActivity.class. How do I pass HashMap values without using intent?
This is how I save my HashMap values which is stored on my SMSReceiver.class.
private HashMap<String, Double> coordinates = new HashMap<String, Double>();
DatabaseReference mRef = databaseLocation.push();
double latitudedb = Double.parseDouble(separatedSMS[1]);
double longitudedb = Double.parseDouble(separatedSMS[3]);
coordinates.put("latitude", latitudedb);
coordinates.put("longitude", longitudedb);
I wanted to get the HashMap values to my MapActivity.class so I would be able to place a marker on my map which positions to actual coordinates I am receiving.
you can use a class and static value for this :
public class CommunActivit {
private static HashMap<String, Float> ListOf;
static {
ListOf = new HashMap<>();
}
public static HashMap<String, Float> getListOf() {
return ListOf;
}
public static void setListOf(HashMap<String, Float> listOf) {
ListOf = listOf;
}
}
Create an instance of CommunActivit in your activity
By exemple :
CommunActivit obj = new CommunActivit();
When you get your coordinates, you can simply call the obj.setListOf(yourhashmap) and when you want to get it, simply call yourhashmap = obj.getListOf();
I use this in my app and it works fine.
I have a fairly simple question, how would I name a variable using another variable.
For example:
public static void addSortListItem(int group_id) {
if (lists.contains(group_id)) {
// add item to correct array list
} else {
lists.add(group_id);
// create new array list using the group_id value as name identifier
ArrayList<ExpListObject> group_id = new ArrayList<ExpListObject>();
}
}
In this function I need to create a new arrayList using the group_id integer as the name. The error here is obviously a duplicate local variable, but what is the correct way to name this?
Any help is appreciated!
You are using group_id as both an identifier name and parameter name. That doesn't make sense. Instead, map the new ArrayList to the group_id. For example:
HashMap<Integer,ArrayList<ExpListObject>> hm = new HashMap<Integer,ArrayList<ExpListObject>>();
hm.put(group_id, new ArrayList<ExpListObject>());
You can make something like this using HashMap, this way:
public static void addSortListItem(int group_id) {
//Create a HashMap to storage your lists
HashMap<String, ArrayList<ExpListObject>> mapList = new HashMap<String, ArrayList<ExpListObject>>();
ArrayList<Object> array = mapList.get(String.valueOf(group_id));
if (array != null) {
array.add(new ExpListObject());
} else {
// Insert the new Array into the HashMap
mapList.put(String.valueOf(group_id), new ArrayList<ExpListObject>());
}
}
Or this way:
public static void addSortListItem(int group_id) {
//Create a HashMap to storage your lists
HashMap< Integer, ArrayList<ExpListObject>> mapList = new HashMap< Integer, ArrayList<ExpListObject>>();
ArrayList<Object> array = mapList.get(group_id);
if (array != null) {
array.add(new ExpListObject());
} else {
// Insert the new Array into the HashMap
mapList.put(group_id, new ArrayList<ExpListObject>());
}
}
I have an array of HashMaps, how to find a particular HashMap entry given a key that is within one of the HashMap entries?
For example, I have this:
ArrayList<HashMap<String, String>> bathroomList = new ArrayList<HashMap<String, String>>();
I also know a key within one of the array entries I want to find:
String selectedKey = ((TextView) view.findViewById(R.id.key)).getText().toString();
How do I iterate the array to find it?
Any help appreciated.
A map is a dictionary. For each key, it has one and only one entry. And there's no point in iterating over a map to find a key, since the whole point af a map is to be able to get the entry for a key in a single method call (O(1) for a HashMap):
String value = map.get(selectedKey)
will get you the value associated with selectedKey in the map.
You want something like a regular for loop to iterate over the arraylist and then just check for null You cannot iterate over a hashmap but if you look for a key and it is not there then it will just return null.
ArrayList< HashMap< String, Object>> bathroomList; //this must be initialized.
public String getEntry(String key) {
int count = bathroomList.length(); // this might be size i can never
// remember
String result = null;
for (int i = 0; i < count; i++) {
result = ((String) bathroomList[i].get(key));
if (result != null) {
break;
}
}
if(result == null){
result = "Key Not Found";
}
return result;
}
Edit to map hashmaps.
public HashMap<String, String> getData(String key) {
String[] hashmapKeys = {"key1", "key2", "key3"};
if(key.equals("key1"){
return bathroomList[0];
}
if(key.equals("key2"){
return bathroomList[1];
}
if(key.equals("key3"){
return bathroomList[2];
}
}
Might i suggest using a different data structure. If you already know that you are maping things with keys then instead of an ArrayList< HashMap< String, String > > you could use a HashMap< String, HashMap<String, String>>
HashMap< String, HashMap<String, String>> bathroomList;
then to get your dataset use
HashMap<String, String>> dataSelected =bathroomList.get(selectedKey);`
Most of the time when you pick something out of a list you will use the arraylist because you pass in the position of the list that the user clicked on. The position in the list is what determines what data was selected anyways.
I have a problem on arraylist and hashmap
As according to my requirement, I am storing the data into HashMap and after that I have created a List as List>.
HashMap<String,String> hashmap;
static List<HashMap<String,String>> hashmap_string;
And while retrieving the value from database and putting it on HashMap and ArrayList like:
contract_number=c.getString(c1);
Log.i("c1.getString,contract_number", contract_number);
String service_level=c.getString(c2);
hashmap=new HashMap<String, String>();
hashmap.put(contract_number, service_level);
hashmap_string.add(hashmap);
And now I want to retrieve the value as String,String
And when I am applying the code as:
for(int i=0;i<hashmap_string.size();i++)
{
Log.i("arraylist", ""+hashmap_string.get(i));
}
I am getting a single string value in the formet as
{Contract,ServiveValue}
but I want to split this into 2 string values...Also these values are redundant and if am using hashMap then it will not showing me the redundant value.
Please help me on this..
It seems you are missing something. When you execute hashmap_string.get(i), you will get the <HashMap<String,String>. So, This is the right value from code.
What you can do is :
HashMap<String, String> hashMap2 = hashmap_string.get(i);
String value = hashMap2.get("your_key");
Other way, you already have two splited string values. you can get that by using keySet() and values() methods over hashMap2 Object.
HashMap (and Maps in general) are used for multiple one-to-one mappings of keys and values. Are you sure you need that? Looking at your code it appears you're using the map as a "Pair" class. I would skip the list, and put everything in the same map, and then iterate over the pairs in the map:
// using tree map to have entries sorted on the key,
// rather than the key's hash value.
Map<String, String> data = new TreeMap<String, String>();
data.put("c1", "s1");
data.put("c2", "s2");
for (Map.Entry<String, String> entry : data.entrySet()) {
String contract = entry.getKey();
String level = entry.getValue();
Log.i("data", contract + " : " + level");
}
would output (assuming TreeSet):
c1 : s1
c2 : s2
Alternatively, create e.g. a ContractServiceLevel class that holds two strings (the contract number and the service level), and put instances of that class in your list.
EDIT:
public final class ContractServiceLevel {
public final String number;
public final String serviceLevel;
public ContractServiceLevel(String c, String s) {
number = c;
serviceLevel = s;
}
}
List<ContractServiceLevel> contracts = new ArrayList<ContractServiceLevel>();
contracts.add(new ContractServiceLevel("c1", "s1.1"));
contracts.add(new ContractServiceLevel("c1", "s1.2"));
contracts.add(new ContractServiceLevel("c2", "s2.1"));
for (ContractServiceLevel contract : contracts) {
Log.i("data", contract.number + ":" + contract.servicveLevel);
}
would output:
c1 : s1.1
c1 : s1.2
c2 : s2.1
String value = hashmap.get("contract");
u will be getting the value as ServiveValue
I have a Generic Map of Strings (Key, Value) and this field is part of a Bean which I need to be parcelable.
So, I could use the Parcel#writeMap Method. The API Doc says:
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, I could iterate over each Entry in my Map a put it into the Bundle, but I'm still looking for a smarter way doing so. Is there any Method in the Android SDK I'm missing?
At the moment I do it like this:
final Bundle bundle = new Bundle();
final Iterator<Entry<String, String>> iter = links.entrySet().iterator();
while(iter.hasNext())
{
final Entry<String, String> entry =iter.next();
bundle.putString(entry.getKey(), entry.getValue());
}
parcel.writeBundle(bundle);
I ended up doing it a little differently. It follows the pattern you would expect for dealing with Parcelables, so it should be familiar.
public void writeToParcel(Parcel out, int flags){
out.writeInt(map.size());
for(Map.Entry<String,String> entry : map.entrySet()){
out.writeString(entry.getKey());
out.writeString(entry.getValue());
}
}
private MyParcelable(Parcel in){
//initialize your map before
int size = in.readInt();
for(int i = 0; i < size; i++){
String key = in.readString();
String value = in.readString();
map.put(key,value);
}
}
In my application, the order of the keys in the map mattered. I was using a LinkedHashMap to preserve the ordering and doing it this way guaranteed that the keys would appear in the same order after being extracted from the Parcel.
you can try:
bundle.putSerializable(yourSerializableMap);
if your chosen map implements serializable (like HashMap) and then you can use your writeBundle in ease
If both the key and value of the map extend Parcelable, you can have a pretty nifty Generics solution to this:
Code
// For writing to a Parcel
public <K extends Parcelable,V extends Parcelable> void writeParcelableMap(
Parcel parcel, int flags, Map<K, V > map)
{
parcel.writeInt(map.size());
for(Map.Entry<K, V> e : map.entrySet()){
parcel.writeParcelable(e.getKey(), flags);
parcel.writeParcelable(e.getValue(), flags);
}
}
// For reading from a Parcel
public <K extends Parcelable,V extends Parcelable> Map<K,V> readParcelableMap(
Parcel parcel, Class<K> kClass, Class<V> vClass)
{
int size = parcel.readInt();
Map<K, V> map = new HashMap<K, V>(size);
for(int i = 0; i < size; i++){
map.put(kClass.cast(parcel.readParcelable(kClass.getClassLoader())),
vClass.cast(parcel.readParcelable(vClass.getClassLoader())));
}
return map;
}
Usage
// MyClass1 and MyClass2 must extend Parcelable
Map<MyClass1, MyClass2> map;
// Writing to a parcel
writeParcelableMap(parcel, flags, map);
// Reading from a parcel
map = readParcelableMap(parcel, MyClass1.class, MyClass2.class);
Good question. There aren't any methods in the API that I know of other than putSerializable and writeMap. Serialization is not recommended for performance reasons, and writeMap() is also not recommended for somewhat mysterious reasons as you've already pointed out.
I needed to parcel a HashMap today, so I tried my hand at writing some utility methods for parcelling Map to and from a Bundle in the recommended way:
// Usage:
// read map into a HashMap<String,Foo>
links = readMap(parcel, Foo.class);
// another way that lets you use a different Map implementation
links = new SuperDooperMap<String, Foo>;
readMap(links, parcel, Foo.class);
// write map out
writeMap(links, parcel);
////////////////////////////////////////////////////////////////////
// Parcel methods
/**
* Reads a Map from a Parcel that was stored using a String array and a Bundle.
*
* #param in the Parcel to retrieve the map from
* #param type the class used for the value objects in the map, equivalent to V.class before type erasure
* #return a map containing the items retrieved from the parcel
*/
public static <V extends Parcelable> Map<String,V> readMap(Parcel in, Class<? extends V> type) {
Map<String,V> map = new HashMap<String,V>();
if(in != null) {
String[] keys = in.createStringArray();
Bundle bundle = in.readBundle(type.getClassLoader());
for(String key : keys)
map.put(key, type.cast(bundle.getParcelable(key)));
}
return map;
}
/**
* Reads into an existing Map from a Parcel that was stored using a String array and a Bundle.
*
* #param map the Map<String,V> that will receive the items from the parcel
* #param in the Parcel to retrieve the map from
* #param type the class used for the value objects in the map, equivalent to V.class before type erasure
*/
public static <V extends Parcelable> void readMap(Map<String,V> map, Parcel in, Class<V> type) {
if(map != null) {
map.clear();
if(in != null) {
String[] keys = in.createStringArray();
Bundle bundle = in.readBundle(type.getClassLoader());
for(String key : keys)
map.put(key, type.cast(bundle.getParcelable(key)));
}
}
}
/**
* Writes a Map to a Parcel using a String array and a Bundle.
*
* #param map the Map<String,V> to store in the parcel
* #param out the Parcel to store the map in
*/
public static void writeMap(Map<String,? extends Parcelable> map, Parcel out) {
if(map != null && map.size() > 0) {
/*
Set<String> keySet = map.keySet();
Bundle b = new Bundle();
for(String key : keySet)
b.putParcelable(key, map.get(key));
String[] array = keySet.toArray(new String[keySet.size()]);
out.writeStringArray(array);
out.writeBundle(b);
/*/
// alternative using an entrySet, keeping output data format the same
// (if you don't need to preserve the data format, you might prefer to just write the key-value pairs directly to the parcel)
Bundle bundle = new Bundle();
for(Map.Entry<String, ? extends Parcelable> entry : map.entrySet()) {
bundle.putParcelable(entry.getKey(), entry.getValue());
}
final Set<String> keySet = map.keySet();
final String[] array = keySet.toArray(new String[keySet.size()]);
out.writeStringArray(array);
out.writeBundle(bundle);
/**/
}
else {
//String[] array = Collections.<String>emptySet().toArray(new String[0]);
// you can use a static instance of String[0] here instead
out.writeStringArray(new String[0]);
out.writeBundle(Bundle.EMPTY);
}
}
Edit: modified writeMap to use an entrySet while preserving the same data format as in my original answer (shown on the other side of the toggle comment). If you don't need or want to preserve read compatibility, it may be simpler to just store the key-value pairs on each iteration, as in #bcorso and #Anthony Naddeo's answers.
If your map's key is String, you can just use Bundle, as it mentioned in javadocs:
/**
* Please use {#link #writeBundle} 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 {#link #writeValue} and must follow
* the specification there.
*
* <p>It is strongly recommended to use {#link #writeBundle} 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.
*/
public final void writeMap(Map val) {
writeMapInternal((Map<String, Object>) val);
}
So I wrote the following code:
private void writeMapAsBundle(Parcel dest, Map<String, Serializable> map) {
Bundle bundle = new Bundle();
for (Map.Entry<String, Serializable> entry : map.entrySet()) {
bundle.putSerializable(entry.getKey(), entry.getValue());
}
dest.writeBundle(bundle);
}
private void readMapFromBundle(Parcel in, Map<String, Serializable> map, ClassLoader keyClassLoader) {
Bundle bundle = in.readBundle(keyClassLoader);
for (String key : bundle.keySet()) {
map.put(key, bundle.getSerializable(key));
}
}
Accordingly, you can use Parcelable instead of Serializable
Here's mine somewhat simple but working so far for me implementation in Kotlin. It can be modified easily if it doesn't satisfy one needs
But don't forget that K,V must be Parcelable if different than the usual String, Int,... etc
Write
parcel.writeMap(map)
Read
parcel.readMap(map)
The read overlaod
fun<K,V> Parcel.readMap(map: MutableMap<K,V>) : MutableMap<K,V>{
val tempMap = LinkedHashMap<Any?,Any?>()
readMap(tempMap, map.javaClass.classLoader)
tempMap.forEach {
map[it.key as K] = it.value as V
}
/* It populates and returns the map as well
(useful for constructor parameters inits)*/
return map
}
All the solutions mentioned here are valid but no one is universal enough. Often you have maps containing Strings, Integers, Floats etc. values and/or keys. In such a case you can't use <... extends Parcelable> and I don't want to write custom methods for any other key/value combinations. For that case you can use this code:
#FunctionalInterface
public interface ParcelWriter<T> {
void writeToParcel(#NonNull final T value,
#NonNull final Parcel parcel, final int flags);
}
#FunctionalInterface
public interface ParcelReader<T> {
T readFromParcel(#NonNull final Parcel parcel);
}
public static <K, V> void writeParcelableMap(
#NonNull final Map<K, V> map,
#NonNull final Parcel parcel,
final int flags,
#NonNull final ParcelWriter<Map.Entry<K, V>> parcelWriter) {
parcel.writeInt(map.size());
for (final Map.Entry<K, V> e : map.entrySet()) {
parcelWriter.writeToParcel(e, parcel, flags);
}
}
public static <K, V> Map<K, V> readParcelableMap(
#NonNull final Parcel parcel,
#NonNull final ParcelReader<Map.Entry<K, V>> parcelReader) {
int size = parcel.readInt();
final Map<K, V> map = new HashMap<>(size);
for (int i = 0; i < size; i++) {
final Map.Entry<K, V> value = parcelReader.readFromParcel(parcel);
map.put(value.getKey(), value.getValue());
}
return map;
}
It's more verbose but universal. Here is the write usage:
writeParcelableMap(map, dest, flags, (mapEntry, parcel, __) -> {
parcel.write...; //key from mapEntry
parcel.write...; //value from mapEntry
});
and read:
map = readParcelableMap(in, parcel ->
new AbstractMap.SimpleEntry<>(parcel.read... /*key*/, parcel.read... /*value*/)
);