21

I'm trying to port my application to the new Google Maps API v2, but i'm having trouble when interacting with markers.

My context: I have a map showing buses and buses stop. With the old library I had my own ItemizedOverlay for bus stops and another one for buses. Each one had a different OnTapListener (actually I use an external library to show balloons), so when the user taps the bus marker nothing happens, but when he taps the bus stop marker an activity with its information is opened. Also, in my ItemizedOverlay I mapped each marker with its bus stop object of the model.

Now with the new API I have 2 main problems:

  • You set a listener with setOnInfoWindowClickListener() or setOnMarkerClickListener() methods of your GoogleMap object. In other words, you can only set one listener for the whole maps, so I can't differentiate between taps on bus stops or buses.
  • The onClick method of both markers receive only the Marker object, from where I can't get too much information like the bus stop number to open its activity (and I hope there is a better way than parsing the title String! O_O)

I think these two problems could be resolved using different subclases of Marker, but it has no constructor and you get its reference when adding it to the map, so I don't know if it's possible to use a custom implementation.

The API is new so there isn't much information on the web about similar problems. I've been trying to figure out how to solve this, but I got nothing. Does anyone know a possible solution to this?

Thanks.

EDIT: A screenshot from my current application's map with two types of markers: A screenshot from my current application's map with two types of marker

Sloy
  • 2,975
  • 3
  • 20
  • 21
  • Thinking about it twice... the Marker class is final, so no way to use subclases :( – Sloy Dec 04 '12 at 23:31
  • This is exactly the thing I just got stuck on too! I was about to ask the question myself but you were faster. How should we pass data to the markers? – martinpelant Dec 05 '12 at 00:07

4 Answers4

24

I have run into this problem as well. My solution was:

private Map<Marker, MyModel> markerMap = new HashMap<>();
private GoogleMap mMap;

private void doMarkers(){
    MarkerOptions opt = new MarkerOptions();
    //Fill out opt from MyModel
    Marker marker = mMap.addMarker(opt);
    markerMap.put(marker, myModel);
}

and then in the OnMarkerClickListener callback, pull your model out of the HashMap using the clicked marker. There is also a method Marker.getId() which for some reason returns a string. I don't understand why you can't specify an int id when you make the marker, or why you can't access the marker object before you add it to the map.

UPDATE: After almost 4 years Google have added a method Marker.setTag(Object tag) to associate arbitrary data with a marker.

rockgecko
  • 4,127
  • 2
  • 18
  • 31
  • 5
    You can also use a WeakHashMap to make sure the marker is not referenced anymore once removed from the map – nicopico Dec 05 '12 at 00:15
  • But is this the proper way to handle it? – martinpelant Dec 05 '12 at 00:51
  • 1
    Yes, that works. I will make a more general solution, kind of a utility class for everyone to use directly. But I'll mark your answer as the good one, thanks ;) – Sloy Dec 05 '12 at 09:43
  • 2
    Are you sure this is the correct answer? According to description of `getId` https://developers.google.com/maps/documentation/android/reference/com/google/android/gms/maps/model/Marker#getId%28%29 . Map and Markers can be restored from `android.os.Bundle` and if so then markers in map `markerMap` are not valid any more ? – MichK Dec 06 '12 at 08:37
  • 10
    It would be nice if Marker object could be extended or if it had some sort of `setTag()` method. – dnkoutso Dec 12 '12 at 20:22
  • 2
    @nicopico Wouldn't a WeakHashMap start removing items immediately because the only reference to the Marker object itself goes out of scope at the end of this method? The MarkerOptions is passed into the map and the Marker is returned. Who knows what happens internally to these objects. I tried it this way adding 20 data items to a map, and when I tap on an InfoWindow my markers collection only contains 3 items (17 have been cleaned up). I switched to a regular HashMap and just clear it every time the data refreshes. I'll probably also clear it in onDestroyView or something – Rich Jan 29 '13 at 01:57
  • 1
    I assumed that the GoogleMap object would keep reference to the Markers, but if that is not the case then you are right, you cannot use a WeakHashMap... – nicopico Jan 29 '13 at 12:26
18

Ok here is a solution which I decided to use and AFAIK should work for any situation:

private HashMap<String, MyModel> markers= new HashMap<String, MyModel>();


MyModel item = ...
MarkerOptions markerOptions = ...
markers.put(mMap.addMarker(markerOptions).getId(), item);



@Override
public void onInfoWindowClick(Marker marker) {
   MyModel mapItem = (MyModel) markers.get(marker.getId());.
   ...
}
martinpelant
  • 2,961
  • 1
  • 30
  • 39
  • 1
    i can confirm that using getId to hold models in Map is the right way to go! thnx for the answers – Yilmaz Guleryuz Jan 31 '13 at 15:16
  • I'm doing the same but building an id with the MarkerOptions name and location, because the marker id is pretty useless in my opinion. This way I can for example check if a Marker is already in the HashMap before inserting it. This is of course because in my model name + locaton are unique – alex Feb 09 '13 at 13:32
2

You can use the marker's getId method

Romain Francois
  • 17,432
  • 3
  • 51
  • 77
ignacio_gs
  • 378
  • 1
  • 7
0

You can use the HashMarker like that. In this example y charge points in Arraylist and each points cointaints a new ArrayList with coordinates. And the idea is you get de point ID.

Create a HashMap

Markers = new HashMap();

Then you create a Marker and add to the map

final Marker marker = map.addMarker(new MarkerOptions().position(new LatLng(coordinates.get(j).getLat(),coordinates.get(j).getLon())).title(point.getName()));

Then you can save the point id with de marker value

Markers.put(marker, point.getId());

And final you can get the id value when you click the InfoWindow

public void onInfoWindowClick(Marker marker) {

    final long id = Marcadores.get(marker);
    Log.e("Real Marker ID", id+"");
}

OR

When you click the marker

public boolean onMarkerClick(Marker arg0) {

    final long id = Marcadores.get(marker);
    Log.e("Real Marker ID", id+"");
    return false;
}
Ciro Mine
  • 819
  • 8
  • 15