I am working with osmdroid library and android http request. So what I am doing is populating a map with markers where the lat and long are obtained from a database on the server. The question id: How can I call to marker.setOnClickListener out of the method where I do the request.
Here's my code:
RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONArray obj = new JSONArray(response);
for (int i = 0; i < obj.length(); i++) {
JSONObject primer = obj.getJSONObject(i);
double latitud = primer.getDouble(TAG_Latitud);
double longitude = primer.getDouble(TAG_Longitude);
marker = new Marker(map);
marker.setPosition(new GeoPoint(latitud, longitude));
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
mHashMap.put(marker, i);
Terrenos.add(terrenos);
}
marker.setOnMarkerClickListener(new Marker.OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker marker, MapView mapView) {
Intent intent = new Intent(Osmdroid.this, Activity2.class);
startActivity(intent);
return false;
}
});
map.getOverlays().add(marker);
} catch (JSONException e) {
Toast.makeText(Osmdroid.this,"Something Wrong", Toast.LENGTH_LONG).show();
Log.w("exception", e.toString());
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(Osmdroid.this,"Something Wrong",Toast.LENGTH_LONG).show();
Log.w("Error", "No hay respuesta en http");
}
});
queue.add(stringRequest);
}
So, in the code above I create the marker inside the 'for', and I am calling the onClick method when it finished. But when I do this not all the marker works when on click, only the last one created.
Does somebody knows what to do? Please, I really would appreciate your help.
I'll try to explain in details, what are you doing wrong, because it seems that you are missing some basics about OOP programing, variables etc.
What's wrong:
You create multiple objects of type Marker in your loop, but variable named marker stores a reference to only one object of type Marker. You are reusing this variable in you loop end during each iteration you assign another instance of class Marker (another object of type Marker, with its own personal chunk of memory).
Once the loop finishes, your variable still exists and points to one object - and it's the last one Marker instance created, because it was the last value assigned to the variable named marker. You are assigning OnMarkerClickListener to this one and only object.
How to fix it
You want to call method setOnMarkerClickListener (assign OnMarkerClickListener) on every instance of Marker you have created. The way to do it is the same as with the creation: use a loop. You have basically 2 options here:
1) Reuse loop which is already in code and assign listener there. It's the simplest solution, because you can just move the assignment a little bit up in your source code and it would work:
for (int i = 0; i < obj.length(); i++) {
JSONObject primer = obj.getJSONObject(i);
double latitud = primer.getDouble(TAG_Latitud);
double longitude = primer.getDouble(TAG_Longitude);
marker = new Marker(map);
marker.setPosition(new GeoPoint(latitud, longitude));
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
mHashMap.put(marker, i);
Terrenos.add(terrenos);
marker.setOnMarkerClickListener(new Marker.OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker marker, MapView mapView) {
Intent intent = new Intent(Osmdroid.this, Activity2.class);
startActivity(intent);
return false;
}
});
}
map.getOverlays().add(marker);
This is not the most optimal way how to do it though. There is new instance of listener created for each marker, so a little bit of memory is wasted. But you can create an instance of listener before loop, store it in variable and assign the same object to all markers. Try to figure it out as an improvement, once you get things working.
2) You can store markers somewhere and create another loop where you'll assign the listener(s). You can have an variable (or a field in your class) containing list of all markers
List<Marker> markers = new ArrayList<>();
In loop, once a marker is created you can add it to this list:
for (int i = 0; i < obj.length(); i++) {
...
marker = new Marker(map);
marker.setPosition(new GeoPoint(latitud, longitude));
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
markers.add(marker); //addind to the listt
...
Than you can iterate over the list later and assign listener to all of markers. Try to figure the code yourself. There will be similar decision as in previous case: you can create new listener for each marker or reuse one for all of them.
And the last thing: you don't need to craete new variable with list as I mentioned above, because you already have field which contains all your markers. You are using them as keys in a hasmmap:
mHashMap.put(marker, i);
I don't know what is a purpose of this hashmap, but you can get access to all markers (exactly: to an instance of Set with all markers) via mHasnMap.keySet()
Only the last marker has onClick because you set it just to it.
in every looping, the marker object gets a new reference marker = new Marker(map);. Because of that at the last looping, the marker object contains the last references and the onClick method sets just to it.
To solve that you just need to set the onClickand the map.getOverlays().add(marker) inside the loop.
public void onResponse(String response) {
try {
JSONArray obj = new JSONArray(response);
for (int i = 0; i < obj.length(); i++) {
JSONObject primer = obj.getJSONObject(i);
double latitud = primer.getDouble(TAG_Latitud);
double longitude = primer.getDouble(TAG_Longitude);
marker = new Marker(map);
marker.setPosition(new GeoPoint(latitud, longitude));
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
map.getOverlays().add(marker);
mHashMap.put(marker, i);
Terrenos.add(terrenos);
marker.setOnMarkerClickListener(new Marker.OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker marker, MapView mapView) {
Intent intent = new Intent(Osmdroid.this, Activity2.class);
startActivity(intent);
return false;
}
});
}
Related
I have a Global array Object like Marker marker_array[]; and later in Layout click I initialized it as marker_array = new Marker[8];. I want to add markers to map on that layout and remove on 2nd click so I created clickcount Global variable with zero value.
My proper code is here
final RelativeLayout layout = (RelativeLayout) findViewById(R.id.track_div);
layout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
clickcount++;
point_new = new LatLng[8];
point_new[0] = new LatLng(31.5301843, 74.3207487);
point_new[1] = new LatLng(31.5214693,74.3236027);
point_new[2] = new LatLng(31.5194393, 74.3257327);
point_new[3] = new LatLng(31.4942166, 74.3004533);
point_new[4] = new LatLng(31.4864646, 74.2911203);
point_new[5] = new LatLng(31.4803596, 74.2787933);
point_new[6] = new LatLng(31.4764716, 74.2638203);
point_new[7] = new LatLng(31.4775236, 74.2628873);
// initialize marker_array;
marker_array = new Marker[8];
Toast.makeText(getApplicationContext(), "count "+clickcount, Toast.LENGTH_SHORT).show();
//
if (clickcount % 2 == 0) {
polyline.setVisible(false);
for (int i = 0; i < point_new.length; i++){
Toast.makeText(getApplicationContext(), "marker length ="+marker_array.length, Toast.LENGTH_SHORT).show();
marker_array[i].remove();
// marker_array.setVisible(false);
}
} else {
polyline.setVisible(true);
for (int i = 0; i < point_new.length; i++) {
// marker_array = new Marker[point_new.length];
MarkerOptions markerOptions = new MarkerOptions()
.position(point_new[i]);
marker_array[i] = mMap.addMarker(markerOptions);
marker_array[i].setTitle("Points");
marker_array[i].setSnippet("Distance = 9.6 km, Time = 20 minute/s");
marker_array[i].setIcon(BitmapDescriptorFactory.fromResource(R.drawable.bus));
}
}
The problem is that it creates all 8 markers But does not remove, Even if in if condition where I'm trying to remove markers Toast shows proper length 8. Butt when I remove any of the marker_array separately as marker_array[7] it removes it.
How can I remove all the markers in marker_array without map.clear(); method because I have some other things like polyline etc that I do not want to remove.
Any effort will be appreciated.
Use this to add markers
As Global
List<Marker> mMarkers = new ArrayList<Marker>();
And In your for loop add markers to this list like
for (int i = 0; i < point_new.length; i++) {
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(point_new[i]);
Marker marker = mMap.addMarker(markerOptions);
marker.setTitle("Point");
marker.setSnippet("this is snippet");
marker.setIcon(BitmapDescriptorFactory.fromResource(R.drawable.p));
mMarkers.add(marker); // <-- Like this
}
And to remove markers
private void removeMarkers() {
for (Marker marker: mMarkers) {
marker.remove();
}
mMarkers.clear();
}
hope it will help.
Try this,
private ArrayList<Marker> mMarkers;
...
private void removeMarkers() {
for (Marker marker: mMarkers) {
marker.remove();
}
mMarkers.clear();
}
The method signature for addMarker is:
public final Marker addMarker (MarkerOptions options)
So when you add a marker to a GoogleMap by specifying the options for the marker, you should save the Marker object that is returned (instead of the MarkerOptions object that you used to create it). This object allows you to change the marker state later on. When you are finished with the marker, you can call Marker.remove() to remove it from the map.
As an aside, if you only want to hide it temporarily, you can toggle the visibility of the marker by calling Marker.setVisible(boolean).
Similar to Remove a marker from a GoogleMap
marker.setVisible(false) worked flawlessly for me for hidding the markers, and I have returned all of them with the marker.setVisible(true). The .clear() was slowing my app a lot. I do not recomend it.
Problem : My remote server returns 10 multiple value for a request.i parsed my response and using for loop i added markers(here i added info to title and snippet) on a map.(here i want to add extra data to marker so that i can access it in on info window click event)
in infoWindowClickListener i want to access that extra data.
How to add extra data to marker/ how to access ph data for a particular marker click(other wise i will get last value of ph in all markers).
i tried like this.
private class HttpGetTask extends AsyncTask<Void, Void, String>
{
//URL and http stuff
}
#Override
protected void onPostExecute(String result) {
try {
json = new JSONArray(result);
for (int i = 0; i < json.length(); i++) {
Log.v("Response", result);
final JSONObject e = json.getJSONObject(i);
String point = e.getString("point");
Log.v("POINT", point);//Checking points
String phone1 = e.getString("ph");
Log.v("PH", phone1);//Checking phone numbers
String[] point2 = point.split(",");//Splitting points
double lat1 = Double.parseDouble(point2[0]);
double lng1 = Double.parseDouble(point2[1]);
Log.v("LLDN", "" + lat1 + "&" + lng1);
//Adding multiple markers
//can i add extra information here along with title and snippet
gMap.addMarker(new MarkerOptions()
.title(e.getString("name"))
.snippet(
e.getString("LS")+""+e.getString("ph") )
.position(new LatLng(lng1, lat1))
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.pmr)));
}
} catch (JSONException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
is it possible to attach extra value to a marker, along with title and snippet.?
or am i parsing in wrong way.?
While #worawee.s's will work perfectly fine, there is a more elegant solution that can allow you to add additional informations to a Marker object. So to solve this, you can use Marker's setTag (Object tag) method:
You can use this property to associate an arbitrary Object with this marker. For example, the Object can contain data about what the marker represents. This is easier than storing a separate Map. As another example, you can associate a String ID corresponding to the ID from a data set.
Not the best solution but this what I do in my application.
create markersMap as a private field in your activity/fragment.
private Map<Marker, ExtraDataObj> markersMap = new HashMap<Marker, ExtraDataObj>();
When you generate marker also put the marker and extra data in your markersMap
ExtraDataObj extraDataObj = new ExtraDataObj();
// extract and store all data you want in the extraDataObj
....
...
..
Marker marker = gMap.addMarker(new MarkerOptions()
.title(e.getString("name"))
.snippet(
e.getString("LS")+""+e.getString("ph") )
.position(new LatLng(lng1, lat1))
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.pmr)));
markersMap.put(marker, extraDataObj);
in your onInfoWindowClick get extra data from the markersMap
ExtraDataObj extraDataObj = markersMap.get(arg0)
I need to add a given number of markers to a map using a for loop. The Log messages tell me the function to add each marker is called, but only one marker (two at most) are displayed on the map. My two functions are the following:
private void paintInMap(String description){
map.clear(); // to erase previous markers
String[] zones = getResources().getStringArray(R.array.zonas); // array of place names
String[] coord = getResources().getStringArray(R.array.coordinates); // array of place coordinates (placed in the same order)
String[] route = description.split(", "); // split the different places of the route description
for(int i=0; i<route.length; i++){
for(int j=0; j<zones.length; j++{
if(route[i].equals(zones[j])){
LatLng latLng = getCoordinates(coord[j]); // call function to get coordinates from String
placeMarker(latLng, zones[j]);
}
}
}
}
and:
private void placeMarker(LatLng coordinates, String name){
map.addMarker(new MarkerOptions()
.title(name)
.icon(BitMapDescriptorFactory.fromResource(R.drawable.gpsmap))
.position(coordinates)
.flat(true)
.rotation(90));
Log.d("PLACE", name+" added to map");
}
Apparently my code is correct, but on runtime it only displays one (or two) markers. I have checked the Log messages and the function is being called, but the markers do no appear. Moreover, one of the markers appears in an unspecified location (which corresponds to the first value of the coordinates array by the way)
Is this a runtime bug in Eclipse? How can I solve this?
map.clear(); // to erase previous markers
new AsyncTask<String, MarkerOptions, Void>() {
private void placeMarker(LatLng coordinates, String name) {
publishProgress(new MarkerOptions()
.title(name)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.gpsmap))
.position(coordinates)
.flat(true)
.rotation(90));
Log.d("PLACE", name + " added to map");
}
#Override
protected Void doInBackground(String... params) {
String[] zones = getResources().getStringArray(R.array.zonas); // array of place names
String[] coord = getResources().getStringArray(R.array.coordinates); // array of place coordinates (placed in the same order)
String[] route = params[0].split(", "); // split the different places of the route description
for (int i=0; i<route.length; i++) {
for (int j=0; j<zones.length; j++) {
if (route[i].equals(zones[j])) {
LatLng latLng = getCoordinates(coord[j]); // call function to get coordinates from String
placeMarker(latLng, zones[j]);
}
}
}
return null;
}
#Override
protected void onProgressUpdate(MarkerOptions... markers) {
map.addMarker(markers[0]);
}
}.execute(description);
I finally solved it by running the for loop in the UI thread instead of doing it using an AsyncTask
......
route = descriptionRoute.split(", ");
coordinates = getCoordinates(coord);
String[] zonas = getResources().getStringArray(R.array.array_zonas_madrid);
String[] coord = getResources().getStringArray(R.array.array_coordinates);
for(int i=0; i<route.length; i++){
for(int j=0; j<zonas.length; j++){
if(route[i].equals(zonas[j])){
LatLng latLng = getCoordinates(coord[j]);
placeMarker(latLng, zonas[j]);
}
}
}
....
I was looking for a solution to my problem, i found some info here but i couldn't make it work with my code.
So, i have a google map with markers. The markers are created with JSON information. What i want is to attach a custom value to each marker, so each time a user touches the infowindow, a new activity will open with passed parameters attached to the specific marker.
Here is the JSON parsing and marker creation:
try{
JSONArray jArray = new JSONArray(result);
for(int i=0; i < jArray.length(); i++) {
JSONObject jObject = jArray.getJSONObject(i);
String image = jObject.getString("image");
String title = jObject.getString("title");
String snipet = jObject.getString("snipet");
double lat=jObject.getDouble("lat");
double lng=jObject.getDouble("lng");
addMarkers(lat, lng,image,title,snipet);
} // End Loop
} catch (JSONException e) {
Log.e("JSONException", "Error: " + e.toString());
} // catch (JSONException e)
private void addMarkers( double jLat, double jLng, final String image, final String jTitle,final String jDescription)
{
LatLng jLocation = new LatLng(jLat, jLng);
alertMarkers = theMap.addMarker(new MarkerOptions()
.position(jLocation)
.title(jTitle)
.snippet(jDescription)
.icon(BitmapDescriptorFactory.fromResource(icon)));
theMap.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
#Override
public void onInfoWindowClick(Marker arg0) {
Toast.makeText(MainActivity.this, arg0.getId(), 1000).show();
}}
}
How can assign that extra parameter, i.e image,to the marker so when a user touches the marker, the corresponding image will be used for further processing.
Thanks.
EDIT:
Here what i added to the code above,but something is not right:
Declared at start
HashMap<String, HashMap> extraMarkerInfo = new HashMap<String, HashMap>();
then added a new HashMap:
*alertMarkers = theMap.addMarker(new MarkerOptions()
.position(jLocation)
.title(jTitle)
.snippet(jDescription)
.icon(BitmapDescriptorFactory.fromResource(icon)));*
HashMap<String, Integer> data = new HashMap<String, Integer>();
data.put("id",alertID);
extraMarkerInfo.put(alertMarkers.getId(),data);
public void onInfoWindowClick(Marker arg0) {
HashMap<String, String> marker_data = extraMarkerInfo.get(arg0.getId());
Log.i("test",marker_data.get("id"));
(…)
But i am getting an error :
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at line:
HashMap<String, String> marker_data = extraMarkerInfo.get(arg0.getId());
I am bit confused with HashMaps.
You can maintain your own HashMap<>, mapping the ID value of the Marker (generated by the system, immutable) to its corresponding extra data. Then, on a marker tap, you look up the extra data. You can see this in action in this sample project.
Or, you can shove the string representation of the data (JSON) into the snippet of the Marker, and retrieve it again later on as needed. This will be more overhead, I suspect.
Marker, however, is final and cannot be extended.
I have an iterates data from a JSONArray Object like this:
try{
for (int i = 0; i < arrResponse.length(); ++i){
JSONObject objResponse = arrResponse.getJSONObject(i);
Integer idShop = objResponse.getInt("ID");
String name = objResponse.getString("Name");
String address = objResponse.getString("Address");
Double slat = objResponse.getDouble("lat");
Double slong = objResponse.getDouble("long");
LatLng shopLocation = new LatLng(slat, slong);}}
I use the iterates data (idShop, name, address, etc) to mark the point of interest place on my map with this code below:
map.addMarker(new MarkerOptions()
.position(shopLocation)
.title(idShop+" "+name)
.snippet(address)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_marker_shop)));
Then i put a click listener into every object that created by marker with this code:
map.setOnInfoWindowClickListener(new OnInfoWindowClickListener() {
#Override
public void onInfoWindowClick(Marker marker) {
// TODO Auto-generated method stub
Intent intent = new Intent(OrderActivity.this, Cart1Activity.class);
// intent.putExtra("IDShop", ""+idShop);
startActivity(intent);
}
});
How do I get the "idShop" data when I click on a marker, then passing it to intent? I use this code on setOnInfoWindowClickListener:
intent.putExtra("IDShop", ""+idShop);
But it doesn't get the real data.
With the code above you can simply get title from marker, split it on space character and take first element in the resulting array. This is your id.
int id = Integer.parseInt(marker.getTitle().split(" ")[0]);
Not very oriented on objects...