I want to update my markers positions. Currently I am removing an item and immediately adding it back with new position, but I am not sure that this is the correct approach. What I would like to do is to update this markers position to a new value without removing/adding it back. Is it possible?
I tried with the following:
var cluster_item = iterator.next();
var marker = dis.cluster_renderer.getMarker(cluster_item);
marker.setPosition(new dis.maps.model.LatLng( 0, 0 ));
.. but its like a temporary set, once I zoom out the cluster and other markers re-render and the position is set back to its original.
Current code:
// Updates all items
var items = dis.cluster_manager_algorithm.getItems();
var iterator = items.iterator();
//while ( iterator.hasNext() ) {
if ( iterator.hasNext() ) {
var cluster_item = iterator.next();
dis.cluster_manager.removeItem(cluster_item);
var item = new dis.clustering.ClusterItem({
//rotation: marker.rotation,
getPosition: function () {
return new dis.maps.model.LatLng(new_position.latitude, new_position.longitude);
},
userData: {imei: "some_imei"}
});
dis.cluster_manager.addItem(item);
// update view
dis.cluster_manager.cluster();
}
Lets take simple example of adding marker on my position .Whenever my location changes ,marker will go on that position . -
#Override
public void onLocationChanged(Location location) {
marker.setPosition(new LatLng(location.getLatitude, location.getLongitude ));
}
Now wherever you are getting latlng you can just use marker.setPosition(latlng) .
EDIT
For Bulk markers use .Assume you have arraylist having LatLng locationList<LatLng>.
#Override
public void onMapReady(GoogleMap map) {
for(int i=0 ;i<locationList.size();i++){
map.addMarker(new MarkerOptions()
.position(locationList.get(i))
.title("Marker").icon());
}}
If you want to use ClusterMarker as per Requirement ,you can find simple tutorial here.Also there is a demo app present here.
Related
I trying to set marker visible on the map when I am in range and set invisible when i am not in range. When am moving and enter area marker appear - but when I get out of range marker is still visible. Here is my code onLocationUpdate.
I iterate over my database and adding markers. getDeviceLocation return Ltglng with my current location. I implement this also for GPS provider. Any ideas will be helpfull ty!
locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 1, new LocationListener() {
#Override
public void onLocationChanged(Location location) {
Cursor res = activityA.myDB.getAllData();
while (res.moveToNext()) {
double ltd = Double.valueOf(res.getString(3));
double lng = Double.valueOf(res.getString(4));
LatLng hole = new LatLng(ltd, lng);
Marker marker = mMap.addMarker(new MarkerOptions().position(hole)
.title(res.getString(1)).visible(false));
if (SphericalUtil.computeDistanceBetween(getDeviceLocation(), marker.getPosition()) <3 ) {
marker.setVisible(true);
}
}
}
From what you have provided this is what I can gather.
You are adding the marker (originally set to invisible), and then if it meets your if statement, you make them invisible. The problem is, I don't see any place, where you would make them invisible again, or remove them.
Do you save these markers in your activity? For example in an ArrayList?
I have two suggestions:
1)Either call mMap.clear() before before your while statement. This will clear the map of any markers, and then adds the new ones as they are created.
2)Save all your markers in an ArrayList and then in your onLocationChanged, use a for loop to go through all your markers and make the ones out of range invisible. Here is an example:
for (Marker marker: mMarkerArrayList) {
if (outOfRange()) {
marker.visible(false);
}
}
Here mMarkerArrayList is the ArrayList containing all your markers. outOfRange() is a helper function that returns a boolean if the marker is outOfRange.
Here is the problem:
I want to show the user the best route to reach a marker after the user presses a button inside the infoWindow. The problem is, I can't get the marker's Location data due to some problem with Latlng and Position classes. (I am using the Mapbox example to get the route, so I need two Position values)
So basically, I need to update the variable Destination with the marker's position by clicking a button inside the custom infowindow. Yet I have no idea how can I do that even though going through a lot on searching Google and Stack Overflow. Can someone help me? (Cammack!) Thanks a bunch for the help!
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
// Origem: Rodoviaria
final Position origin = Position.fromCoordinates(-47.882645, -15.794082);
// Destino: Reitoria
final Position destination = Position.fromCoordinates(-47.866611, -15.762604);
//...
mapboxMap.setInfoWindowAdapter(new MapboxMap.InfoWindowAdapter() {
#Nullable
#Override
public View getInfoWindow(#NonNull Marker marker) {
//...
final Marker marcador = marker;
botaoIr = (Button)v.findViewById(R.id.botaoIr);
botaoIr.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//I have been trying the method below, but I am having trouble with LatLng and Position classes!
//LatLng ponto = marcador.getPosition();
//destination = new Position(ponto.getLongitude(),ponto.getLatitude());
try {
getRoute(origin, destination);
} catch (ServicesException servicesException) {
servicesException.printStackTrace();
}
}
});
}
});
//...
}
To create a position call fromCoordinates().
destination = Position.fromCoordinates(ponto.getLongitude(),ponto.getLatitude());
If you want to remove all annotations on your map, you can call "removeAnnotations()" on your MapBoxMap-Instance:
mapboxMap.removeAnnotations();
..or you can call "remove()" on any annotation from MapBox itself (Polygon, Polyline or Marker)
Polygon pol = new Polygon();
pol.remove();
If it's still existing and you just want to change & update an annotation, call "updatePolygon()", "updateMarker" or "updatePolyline() like this:
mapboxMap.updatePolygon(myPolgonInstance);
mapboxMap.updateMarker(myMarkerInstance);
...
I haven't found any complete explanation on how to use this technique on Android so I decided to create a Q&A thread.
If your app has to show a large amount of markers on a google map and clustering them is not enough to prevent your app from working too slow, then one of your best choices is to use this Viewport Marker Management technique. You can read the theoretical explanation here: https://developers.google.com/maps/articles/toomanymarkers
I wrote a short guide below...
1°--- In the activity where map is created you have to set the OnCameraChangeListener and get the bounds of your screen like this:
mMap.setOnCameraChangeListener(new OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition arg0) {
LatLngBounds bounds = mapa.getProjection().getVisibleRegion().latLngBounds;
}
2°--- This step may vary depending how you fetch the markers data. Basically, what you have to do is to calculate if the lat and long of each of your markers are inside the screen bounds. I will show you how to do it by fetching the data from a SQLite data base storing latitud and longitude in two different DOUBLE clomuns inside the markers table.
mMap.setOnCameraChangeListener(new OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition arg0) {
LatLngBounds bounds = mMap.getProjection().getVisibleRegion().latLngBounds;
LatLng northeast = bounds.northeast;
String boundLat = String.valueOf(northeast.latitude);
String boundLong = String.valueOf(northeast.longitude);
LatLng southwest = bounds.southwest;
String boundLat2 = String.valueOf(southwest.latitude);
String boundLong2 = String.valueOf(southwest.longitude);
//Remove all markers from map
mMap.clear(); // or if your a using cluster manager:
//mClusterManager.clearItems();
String[] fields = new String[] { "name", "latitude", "longitude" };
String[] args = new String[] {boundLat, boundLong, boundLat2, boundLong2,};
Cursor markers = dataBase.query("markers", fields, "latitude<=? AND longitude<=? AND latitude>=? AND longitude>=?");
if (markers.moveToFirst()) {
do {
mMap.addMarker(new MarkerOptions()
.position(new LatLng(marker.getDouble(1), marker.getDouble(2)))
.title(marker.getString(0)) );
// or if you are using cluster manager create and add the items as you normaly do.
} while (c.moveToNext());
//if using cluster manager add :
//mClusterManager.cluster();
}
}
});
The idea is pretty easy, just have in mind that your markers lat and longi have to be smaller than the northeast position of your screen and bigger than the southwest corner, or just use the LatLngBounds.contains function.
EDITED:
To avoid InfoWindow getting closed when clicking on a marker which is not already in the center of the screen, you can change the marker click listener default action, removing the camera move.
map.setOnMarkerClickListener(new OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker arg0) {
arg0.showInfoWindow();
return true; //must be true, if not, it will execute the default code after yours
}
});
I need display >100 markers on the map and show info window after click on marker.
I have used android google maps api v2, but it is lagging with such number of markers. So I decided switch to android-maps-extensions. After I did it info window has stopped appear after click on marker.
Here is my code:
private void prepareMap() {
SupportMapFragment fragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.locationsMap);
map = fragment.getExtendedMap();
ClusteringSettings settings = new ClusteringSettings();
settings.clusterOptionsProvider(new ClusterOptionsProvider() {
#Override
public ClusterOptions getClusterOptions(List<Marker> markers) {
float hue = BitmapDescriptorFactory.HUE_RED;
BitmapDescriptor icon = BitmapDescriptorFactory.defaultMarker(hue);
return new ClusterOptions().icon(icon);
}
});
settings.clusterSize(100);
settings.addMarkersDynamically(true);
map.setClustering(settings);
map.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker marker) {
// breakpoint here are working. marker is not null
marker.showInfoWindow();
return false;
}
});
}
public void onLoadFinished(android.support.v4.content.Loader loader, Cursor cursor) {
if (map != null) {
cursor.moveToFirst();
int count = cursor.getCount();
for (int i = 0; i < count; i++) {
Location location = new Location(cursor);
MarkerOptions options = new MarkerOptions();
options.position( new LatLng(location.getLatitude(), location.getLongitude()));
options.title(location.getTitle()); // title is not null
options.snippet(location.getAddress()); // address is not null
options.data(location);
map.addMarker(options);
cursor.moveToNext();
}
}
}
Any suggestions? I have try use own InfoWindowAdapter, but it is not scaling this window for appropriate content, however I am using wrap_content attribute in xml.
As there is no support for setting title on ClusterOptions (yet), you will have to use InfoWindowAdapter (you may put a separate question on why it is not working as you want it) or add title to ClusterOptions yourself and make sure its value is forwarded to virtual marker that represents cluster. This sounds complicated but is fairly easy. You may also want to add issue on GitHub regarding title not being supported for clustrers.
After that you may use something like:
return new ClusterOptions().icon(icon).title("Test");
Then you will have to figure out what title will best fit your needs. You will most likely want to use List<Marker> to calculate title for this group of markers.
Note: If you zoom enough to show separate markers, you can click on them to show title. If not, there is something more wrong in your code.
I have an ArrayList of a custom class. There are about 10 objects in the list, each with details like Title, Snippet, LatLng. I have successfully added all 10 to a Map by using my custom class functions like getTitle, getSnippet, getLatLng etc.
Now, when I click the info window (of the marker), I want to be able to somehow KNOW which object of my custom class does that marker correspond to.
For example, if I click the McDonald's market, I want to be able to know which item from my ArrayList did that marker belong to.
I've been looking at the MarkerOptions and there doesn't seem to be anything in there that I can use to identify the relevant custom object with.
If the question is too confusing, let me make it simple:
ArrayList<CustomObj> objects = blah
map.addMarker(new MarkerOptions().position(new LatLng(
Double.parseDouble(result.get(i).getCompanyLatLng()
.split(",")[0]), Double.parseDouble(result
.get(i).getCompanyLatLng().split(",")[1])))
.title(result.get(i).getCompanyName())
.snippet(result.get(i).getCompanyType())
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.pin)));
Now when this is clicked, I go on to the next page. The next page needs to know WHICH object was clicked so that I can send the other details to that page (e.g. Image URLs that need to be loaded etc).
How do I add a unique integer or any identifier to my marker?
One correct way is to use Map<Marker, CustomObj> which stores all markers:
Marker marker = map.addMarker(...);
map.put(marker, result.get(i));
and in onInfoWindowClick:
CustomObj obj = map.get(marker);
Another try is using Android Maps Extensions, which add getData and setData method to Marker, so you can assign your CustomObj object after creating marker and retrieve it in any callback.
I used the the snippet text for saving an unique ID. If you need the snippet it's will be for the popup and there you can just make your own (by finding the object from the ID) so you wont miss it but you'll certainly miss a unique ID for identifying the objects.
To find the right object I just iterate through them:
for(SomeObject anObject : someObjects) {
if(marker.getSnippet().equalsIgnoreCase(anObject.getID())) {
//you got at match
}
}
According to the discussion at the following link, Marker.equals and Marker.hashCode don't work sometimes. For example, when the map is panned or zoomed, or it's restarted/resumed.
Add Tag / Identifier to Markers
So Marker's ID is a better key than Marker itself for a HashMap.
Map<String, MyObject> markerMap = new HashMap<String, MyObject>();
Marker marker = map.addMarker(...);
MyObject myObject = new MyObject();
markerMap.put(marker.getId(), myObject);
I think using latitude and longitude, this could be done
map.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
#Override
public boolean onMarkerClick(final Marker marker) {
LatLng pos = marker.getPosition();
int arryListPosition = getArrayListPosition(pos);
return true;
}
});
and the method getArrayListPosition is
private int getArrayListPosition(LatLng pos) {
for (int i = 0; i < result.size(); i++) {
if (pos.latitude == result.get(i).getCompanyLatLng().split(",")[0]) {
if (pos.longitude == result.get(i).getCompanyLatLng()
.split(",")[1])
return i;
}
}
return 0;
}
This method will return you the position of your ArrayList who's Marker you have clicked. and you can get data from that position.
Hope it helps...
I am 4 years late to answer but I really amazed why no-one talked about marker.setTag and marker.getTag method.
As written in google API docs,
This is easier than storing a separate Map<Marker, Object>
They have introduce setTag and getTag to avoid use of Map<...>. You can use it as following way.
Marker marker = map.addMarker(...);
marker.setTag(result.get(i)); //Store your marker information here.
//To fetch your object...
map.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker marker) {
CustomObj obj = (CustomObj)marker.getTag();
//Your click handle event
// Pass the obj to another activity and you are done
return false;
}
});