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.
Related
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.
In my App users use a map to mark their location. When new users want to create their location I would like to prevent them from putting their marker to close to already existing markers, if possible to specify mandatory distance between markers for example 10 or 20 meters.
Thank you.
This is actually very simple, all you need to do is check if the point that the user clicks on is further than your required distance before removing the previous Marker and adding the new one.
You can use the Location.distanceBetween() method to do the distance check.
First, create your Marker reference as an instance variable of the Activity:
Marker marker;
Then, in your OnMapClickListener, add the logic to only move the Marker that the user chooses as the current location if the distance is greater than your defined minimum distance, 20 meters in this example:
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
#Override
public void onMapClick(LatLng point) {
if (marker != null) {
LatLng markerPoint = marker.getPosition();
float[] distance = new float[2];
Location.distanceBetween(point.latitude, point.longitude,
markerPoint.latitude, markerPoint.longitude, distance);
//check if new position is at least 20 meters away from previous selection
if( distance[0] > 20 ){
//remove previous Marker
marker.remove();
//place marker where user just clicked
marker = mMap.addMarker(new MarkerOptions().position(point).title("My Location")
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA)));
}
else{
//Alert the user to select a location further away from the one already selected
Toast.makeText(MainActivity.this, "Please select a different location.", Toast.LENGTH_SHORT).show();
}
}
else {
//No previous selection, place marker where user just clicked
marker = mMap.addMarker(new MarkerOptions().position(point).title("My Location")
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA)));
}
}
});
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
}
});
UPDATE: I have solved the performance issue by adding a previousMarker object. So only the previous clicked marker will be remove and replaced with the default icon. However the info window is still not shown when I click on the marker.
I have a map view and set some markers on it. What I want is when I clicked on a marker, it changes its icon to be a different icon, and when I click on another marker, the previous marker's icon should change to its original one.
What I've done is something like this but it just simply changes the marker icon whenever I click on the marker.
#Override
public boolean onMarkerClick(Marker marker) { //Called when a marker has been clicked or tapped.
LatLng markerPos=marker.getPosition();
String markerLocationName=marker.getTitle();
String markerSubCategoryName=marker.getSnippet();
marker.remove();
MarkerOptions markerOptions =
new MarkerOptions().position(markerPos)
.title(markerLocationName)
.snippet(markerSubCategoryName)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.new_icon));// Changing marker icon
mMap.addMarker(markerOptions);
Log.d("marker","change marker icon"); // can open a dialog window here
return false;
}
So if I click 2 markers, I will get 2 new icons appears, meanwhile what I want is only the current clicked marker changes its icon.
So I've also done something like this by adding 2 more lines of code. It succeeds doing what I want but it has some drawback (see below).
#Override
public boolean onMarkerClick(Marker marker) { //Called when a marker has been clicked or tapped.
mMap.clear();
populateAllMarkersOnMap();//repopulate markers on map
LatLng markerPos=marker.getPosition();
String markerLocationName=marker.getTitle();
String markerSubCategoryName=marker.getSnippet();
marker.remove(); //remove the current clicked marker
MarkerOptions markerOptions =
new MarkerOptions().position(markerPos)
.title(markerLocationName)
.snippet(markerSubCategoryName)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.new_icon));// Changing marker icon
mMap.addMarker(markerOptions); //add marker with new icon into map
return false;
}
The drawback is 1/ it "disable" the info window (the same thing also happen in the first way). 2/ it clear all the markers on map and set all the markers again. Imagine I have 100 markers, should that be a performance problem on every click I do?
The populateAllMarkersOnMap() can be something as simple like this at the moment:
private void populateAllMarkersOnMap(){
setMarker(latA1, lonA1, "A1","A1.1");
setMarker(latA2, lonA2, "A2","A2.1");
// ... (100 times or populated via a loop)
};
So is there a way to get previous clicked marker to change its icon back to default when I click a new marker? Apologise for my English, if you think I should put another title for my question, please help.
Finally I found the best and most simple way. I made a previousMarker object and store the current clicked marker:
#Override
public boolean onMarkerClick(Marker marker) { //Called when a marker has been clicked or tapped.
if(previousMarker!=null){
previousMarker.setIcon(BitmapDescriptorFactory.fromResource(R.drawable.dot_icon));
}
marker.setIcon(BitmapDescriptorFactory.fromResource(R.drawable.ct_icon));
previousMarker=marker; //Now the clicked marker becomes previousMarker
return false;
}
You might be looking for this method probably
Called when the marker's info window is closed.
optional public func mapView(mapView: GMSMapView, didCloseInfoWindowOfMarker marker: GMSMarker)
I found the best and most simple way. I made another marker object and store the current clicked marker enter code here
#Override
public boolean onMarkerClick(Marker marker) { //Called when a marker has been clicked or tapped.
if(previousMarker!=null){
marker2.setIcon(BitmapDescriptorFactory.fromResource(R.drawable.dot_icon));
}
marker.setIcon(BitmapDescriptorFactory.fromResource(R.drawable.ct_icon));
marker2=marker; //Now the clicked marker becomes previousMarker
return false;
}
Is there any possibility to delete certain Google Map markers and having to do map.clear ()? Because in my app I have several checkbox marking and unmarked some markers ...
How can I achieve this?
I have done a similar thing in the past.
The trick is to maintain a list of the Marker objects, but within your own custom class (I have created a class called MapPoint which has the latlng, title, icon, snippet and holds a Marker).
Then when you want to push an update to the map you create a list of MapPoint objects (with the Marker set to null) with the current list of active MapPoint objects, remove duplicates and empty ones that no longer exist. This allows you to update the map as little as possible, rather than doing an entire refresh of everything.
Code snippet with comments for easier reading:
// holds the current list of MapPoint objects
public ArrayList<MapPoint> mCurrentPoints = new ArrayList<MapPoint>();
public void addMapPoints(ArrayList<MapPoint> mapPoints) {
// only process if we have an valid list
if (mapPoints.size() > 0) {
// iterate backwards as we may need to remove entries
for (int i = mCurrentPoints.size() - 1; i >= 0; i--) {
// get the MapPoint at this position
final MapPoint point = mCurrentPoints.get(i);
// check if this point exists in the new list
if (!mapPoints.contains(point)) {
// if it doesn't exist and has a marker (null check), remove
if (point.mMarker != null) {
// removes Marker from mMap
point.mMarker.remove();
}
// remove our MapPoint from the current list
mCurrentPoints.remove(i);
} else {
// already exists, remove from the new list
mapPoints.remove(point);
}
}
// add all the remaining new points to the current list
mCurrentPoints.addAll(mapPoints);
// go through every current point. If no mMarker, create one
for (MapPoint mapPoint : mCurrentPoints) {
if (mapPoint.mMarker == null) {
// create Marker object via mMap, save it to mapPoint
mapPoint.mMarker = mMap.addMarker(new MarkerOptions()
.position(mapPoint.getLatLng())
.title(mapPoint.getTitle())
.icon(mapPoint.getMarker())
.snippet(mapPoint.getInfoSnippetText()));
}
}
}
}
So you will want a method that determines what Marker objects are to be shown, create a MapPoint objects for them, then send the list of them to this addMapPoints() method.
A couple of good ideas: synchronize on the mCurrentPoints list (removed to make code snippet simpler) and ensuring you run on UI thread for the adding/removing markers. (Good idea to do this processing off the main thread then hop on to it for the actual adding/removing of Markers). And adapt to your own situation of course.
Use setVisible(true) on a Marker object (not a MarkerOptions, this is important). Add all the markers you want as visible/invisible, keep the references to the Marker objects, and toggle them on demand.