I am building an android app in which i have to do tracking of a user from one date/time to another and deploy makers using polylines one by one?
In response from a server i am receiving multiple lat/langs in a list. Now i want to deploy them one by one like a video is being played i know how to add markers i just want to control there deployment.E.g Marker A is deployed after 2 secs marker B should be deployed and joining with marker A with a poly-line and so do markers C,D. etc. How should i be able to achieve that. Timer, Threads? Any help or references,algos, would be great although i have searched such examples i couldn't find it yet.
Thanks in advance
You can use Handler to perform this task.
I am posting an example for you, I have not run it but I hope It will run successfully:
private final Handler mHandler = new Handler(Looper.getMainLooper());
private List<LatLng> mLatLngs;
private PutMarkerRunnable mRunnable;
private int mNoOfMarkersPlaced = -1;
private void showMarkers(List<LatLng> latLngs) {
mLatLngs = latLngs;
mHandler.post(mRunnable);
}
private class PutMarkerRunnable implements Runnable {
#Override
public void run() {
// write code to add marker
map.addMarker();
mNoOfMarkersPlaced++;
if (mNoOfMarkersPlaced != mLatLngs.size()) {
// scheduling next marker to be placed after 3 seconds
mHandler.postDelayed(mRunnable, 3000);
}
}
}
Ok thanks community.. But i have been finally able to do this through. Mark it correct because this really worked for me!
First we animate our camera using..
CameraPosition cameraPosition =
new CameraPosition.Builder()
.target(new LatLng(0,0))
.bearing(45)
.tilt(90)
.zoom(googleMap.getCameraPosition().zoom)
.build();
googleMap.animateCamera(
CameraUpdateFactory.newCameraPosition(cameraPosition),
ANIMATE_SPEEED_TURN,
new CancelableCallback() {
#Override
public void onFinish() {
}
#Override
public void onCancel() {
}
}
);/**
*
* Callback that highlights the current marker and keeps animating to the next marker, providing a "next marker" is still available.
* If we've reached the end-marker the animation stops.
*
*/
CancelableCallback simpleAnimationCancelableCallback =
new CancelableCallback(){
#Override
public void onCancel() {
}
#Override
public void onFinish() {
if(++currentPt < markers.size()){
CameraPosition cameraPosition =
new CameraPosition.Builder()
.target(targetLatLng)
.tilt(currentPt<markers.size()-1 ? 90 : 0)
//.bearing((float)heading)
.zoom(googleMap.getCameraPosition().zoom)
.build();
googleMap.animateCamera(
CameraUpdateFactory.newCameraPosition(cameraPosition),
3000,
simpleAnimationCancelableCallback);
highLightMarker(currentPt);
}
}
};
A bearing can be calculated between 2 android.location.Location objects. As we’re working with com.google.android.gms.maps.model.LatLng objects here, we first need to convert them into Location objects.
private Location convertLatLngToLocation(LatLng latLng) {
Location location = new Location("someLoc");
location.setLatitude(latLng.latitude);
location.setLongitude(latLng.longitude);
return location;
}
Once we have 2 Location objects, we can calculate the bearing between the 2. This is what we need to put on the Camera when transitioning to the target (the endLocation).
private float bearingBetweenLatLngs(LatLng beginLatLng,LatLng endLatLng) {
Location beginLocation = convertLatLngToLocation(beginLatLng);
Location endLocation = convertLatLngToLocation(endLatLng);
return beginLocation.bearingTo(endLocation);
}
We’ll use that number to calculate the coordinates of the intermediate point. Once we have those coordinates, we set our tracking marker to that new position.
long elapsed = SystemClock.uptimeMillis() - start;
double t = interpolator.getInterpolation((float)elapsed/ANIMATE_SPEEED);
double lat = t * endLatLng.latitude + (1-t) * beginLatLng.latitude;
double lng = t * endLatLng.longitude + (1-t) * beginLatLng.longitude;
LatLng intermediatePosition = new LatLng(lat, lng);
trackingMarker.setPosition(intermediatePosition);
We’ll also update our polyline with the new marker position, creating a trailing effect on the polyline.
private void updatePolyLine(LatLng latLng) {
List<LatLng> points = polyLine.getPoints();
points.add(latLng);
polyLine.setPoints(points);
}
Related
I have problem about my gps and plot polygon
I collect GPS every second from
Location location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
and put it to realm database
(So I things do I not good idea)
Maybe should accumulate every 10 meters
image below is result I got
my problems
Polygon look alike the PASTA instead of area.
My gps can jump over to another building(GPS is not stable)
help recommend me please.
ArrayList<LatLng> coordList = new ArrayList<LatLng>();
#Cleanup Realm realm = Realm.getDefaultInstance();
RealmResults<PolygonAreas> PlotPolygon = realm.where(PolygonAreas.class).findAll();
if (PlotPolygon.size() > 0) {
for (PolygonAreas Polypoint : PlotPolygon) {
coordList.add(new LatLng(Polypoint.getLatitude(), Polypoint.getLongitude()));
try {
Runnable addPolygon = new CellTowerMarkerGoogle.AddPolygon(mMap, new PolygonOptions()
.addAll(coordList).fillColor(0x7F80b370).strokeColor(0x7F80b370)
);
getActivity().runOnUiThread(addPolygon);
} catch (Exception e) {
log.debug("Exception : " + e);
}
}
}
public static class AddPolygon implements Runnable{
private GoogleMap map;
private PolygonOptions options;
public AddPolygon(GoogleMap map,PolygonOptions options){
this.map = map;
this.options = options;
}
#Override
public void run() { map.addPolygon(options);}
}
I found problem
Because my logic incorrect variable addPolygon
every back again it's create new Object polygon(.addAll)
It causes the creation of overloaded objects.
How can I fix it?
I have to destroy the polygon object and recreate it every time.
The value will be updated all the time. I have to destroy and create new polygons every time to update.
I am using Google Map, now I am showing a polyline b/w my current location to my destination by using Google Direction API with moving marker animation.
Now if I change my path while driving then how can I update that path from my current location to the destination.
Here is my code
#Override
public void onDirectionSuccess(Direction direction, String rawBody) {
if (direction.isOK()) {
route = direction.getRouteList().get(0);
ArrayList<LatLng> directionPositionList = route.getLegList().get(0).getDirectionPoint();
mMap.addPolyline(DirectionConverter.createPolyline(this, directionPositionList, 8, Color.BLUE));
} else {
Toast.makeText(DriversActivity.this, direction.getStatus(), Toast.LENGTH_SHORT).show();
}
Here in OnDirectionSuccess method, m getting the direction. I don't want to call it again and again because the previous line is also there with a new one.
Is anyone can help me out???
please first add this function to activity
private void route(AbstractRouting.TravelMode travelMode, final LatLng end) {
this.end = end;
DataShahrManager dataShahrManager = DataShahrManager.getInstance(activity);
if (dataShahrManager.getMyLocation() != null) {
start = new LatLng(dataShahrManager.getMyLocation().getLatitude(),
dataShahrManager.getMyLocation().getLongitude());
if (end != null) {
mapsFragment.getProgressBar().setVisibility(View.VISIBLE);
Routing routing = new Routing.Builder()
.travelMode(travelMode)
.withListener(this)
.alternativeRoutes(false)
.waypoints(start, end)
.language("fa")
.key("your key")
.build();
routing.execute();
}
} else {
mapsFragment.getLocationProgressBar().setVisibility(View.VISIBLE);
mapsFragment.startLocationFinding();
mapsFragment.setUpMyLocationUsingMap();
if (activity != null) {
Toast.makeText(activity, R.string.finding_your_location, Toast.LENGTH_SHORT).show();
}
mapsFragment.setOnLocationFoundListener(() -> route(AbstractRouting.TravelMode.DRIVING, end));
}
}
so add this line to button
route(AbstractRouting.TravelMode.DRIVING, businessEntity.getLatLng());
I have an activity implementing OnMapReadyCallback to display some markers.
Before opening the map i provide a target city which i'd like to look at closer on the map basically by calling :
LatLng currentCity = new LatLng(cityLat,cityLng)
CameraUpdate location = CameraUpdateFactory.newLatLngZoom(currentCity,13);
googleMap.animateCamera(location);
The main problem here is that the zoom level is just an arbitrary number which works fine for some city and bad for others (Too zoomed in, Not enough zoomed in).
What i would like to achieve is to determine the zoom level dynamically depending on the city in the same way Google Maps does.
I know that the bigger the ViewPort of the city is, the smaller the zoom needs to be but i can't find a method to get the ViewPort for a given city and then changing the zoom level accordingly
EDIT : I was thinking about using a Geocoder to get a list of adress using the latitude and longitude of the city using
List<Address> addresses = mGeocoder.getFromLocation(Lat,Lon,maxLimit);
and then iterating over this list to find out the outermost adresses avaible for that city, in order to build a LatLngBounds to pass at setLatLngBoundsForCameraTarget() method.
The main problem with this approach is that, once again, the "maxLimit" is arbitrary and needs to be quite big for a big city, eventually returning a really big List
You can retrieve a view port for the city from the Geocoding API reverse geocoding response.
You should execute HTTP request to retrieve city view port from your activity. Once you receive the response you can construct the LatLngBounds instance and move camera accordingly.
Sample reverse geocoding request that gets city from coordinates is the following
https://maps.googleapis.com/maps/api/geocode/json?latlng=47.376887%2C8.541694&result_type=locality&key=YOUR_API_KEY
I wrote a small example for Map activity that receives lat and lng from the intent, executes the reverse geocoding HTTP request using the Volley library and moves camera to show the city view port.
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private GoogleMap mMap;
private float lat;
private float lng;
private String name;
private RequestQueue mRequestQueue;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent i = getIntent();
this.lat = i.getFloatExtra("lat", 0);
this.lng = i.getFloatExtra("lng", 0);
this.name = i.getStringExtra("name");
mRequestQueue = Volley.newRequestQueue(this);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// Add a marker in Sydney and move the camera
LatLng pos = new LatLng(this.lat, this.lng);
mMap.addMarker(new MarkerOptions().position(pos).title(this.name));
mMap.moveCamera(CameraUpdateFactory.newLatLng(pos));
this.fetchReverseGeocodeJson();
}
private void fetchReverseGeocodeJson() {
// Pass second argument as "null" for GET requests
JsonObjectRequest req = new JsonObjectRequest(Request.Method.GET,
"https://maps.googleapis.com/maps/api/geocode/json?latlng=" + this.lat + "%2C" + this.lng + "&result_type=locality&key=AIzaSyBrPt88vvoPDDn_imh-RzCXl5Ha2F2LYig",
null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
String status = response.getString("status");
if (status.equals("OK")) {
JSONArray results = response.getJSONArray("results");
JSONObject item = results.getJSONObject(0);
JSONObject geom = item.getJSONObject("geometry");
JSONObject bounds = geom.getJSONObject("viewport");
JSONObject ne = bounds.getJSONObject("northeast");
JSONObject sw = bounds.getJSONObject("southwest");
LatLngBounds mapbounds = new LatLngBounds(new LatLng(sw.getDouble("lat"),sw.getDouble("lng")),
new LatLng(ne.getDouble("lat"), ne.getDouble("lng")));
mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(mapbounds, 0));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.e("Error: ", error.getMessage());
}
}
);
/* Add your Requests to the RequestQueue to execute */
mRequestQueue.add(req);
}
}
You can find a complete sample project at github:
https://github.com/xomena-so/so44735477
Hope this helps!
I am using Mapbox (4.2.1) to draw a line from my position to a target position. I have the intention of using the straight line as an extremely basic navigation aid. As such I am re-drawing the guide line OnMyLocationChanged(). However it appears that as my location changes it will draw the line to my new location but MyLocationView (User icon) does not update in accordance (See image below).
They will eventually end up meeting again but it takes some time. It seems that the line is getting drawn inside the accuracy radius, however I would prefer if it could draw the line straight from the user icon.
Is there a simple way to draw a line between the user (The actual icon on the map) and a location which updates as the user moves?
My OnMyLocationChanged is:
MapboxMap.OnMyLocationChangeListener listner = new MapboxMap.OnMyLocationChangeListener(){
#Override
public void onMyLocationChange(final #Nullable Location locationChanged) {
//If we are not targeting anything or we are not tracking location
if(target == null || !map.isMyLocationEnabled()) return;
mapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(MapboxMap mapboxMap) {
//Log.i("LOC-MAPLINE", "Drawing from mapLoc call");
//Error if we don't have a location
if(!mapboxMap.isMyLocationEnabled() || locationChanged == null) return;
LatLng[] points = new LatLng[2];
final Location myLoc = locationChanged;
LatLng loc = new LatLng(myLoc.getLatitude(), myLoc.getLongitude());
LatLng dest = new LatLng(target.getLatitude(), target.getLongitude());
points[0] = loc;
points[1] = dest;
mapboxMap.removeAnnotations();
loadMarker(target);
PolylineOptions poly = new PolylineOptions()
.add(points)
.color(Color.parseColor("#3887be"))
.width(5);
line = mapboxMap.addPolyline(poly);
}
});
}
};
Any assistance is greatly appreciated, thank you!
EDIT (In regards to possible duplicate question - Google direction route from current location to known location)
I believe my question is different for a few reasons.
I am more concerned on getting the location of the user icon overlay rather than actual location (Accuracy issue)
I am not interested in getting turn for turn directions (Like those from a directions API)
I am using Mapbox rather than google maps (Not too sure but there could be some differences).
Nevertheless that question does not seem to answer my question
According to documentation you need only implement this method passing your currentLocation (origin) and destination
private void getRoute(Position origin, Position destination) throws ServicesException {
MapboxDirections client = new MapboxDirections.Builder()
.setOrigin(origin)
.setDestination(destination)
.setProfile(DirectionsCriteria.PROFILE_CYCLING)
.setAccessToken(MapboxAccountManager.getInstance().getAccessToken())
.build();
client.enqueueCall(new Callback<DirectionsResponse>() {
#Override
public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
// You can get the generic HTTP info about the response
Log.d(TAG, "Response code: " + response.code());
if (response.body() == null) {
Log.e(TAG, "No routes found, make sure you set the right user and access token.");
return;
} else if (response.body().getRoutes().size() < 1) {
Log.e(TAG, "No routes found");
return;
}
// Print some info about the route
currentRoute = response.body().getRoutes().get(0);
Log.d(TAG, "Distance: " + currentRoute.getDistance());
Toast.makeText(
DirectionsActivity.this,
"Route is " + currentRoute.getDistance() + " meters long.",
Toast.LENGTH_SHORT).show();
// Draw the route on the map
drawRoute(currentRoute);
}
#Override
public void onFailure(Call<DirectionsResponse> call, Throwable throwable) {
Log.e(TAG, "Error: " + throwable.getMessage());
Toast.makeText(DirectionsActivity.this, "Error: " + throwable.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
private void drawRoute(DirectionsRoute route) {
// Convert LineString coordinates into LatLng[]
LineString lineString = LineString.fromPolyline(route.getGeometry(), Constants.OSRM_PRECISION_V5);
List<Position> coordinates = lineString.getCoordinates();
LatLng[] points = new LatLng[coordinates.size()];
for (int i = 0; i < coordinates.size(); i++) {
points[i] = new LatLng(
coordinates.get(i).getLatitude(),
coordinates.get(i).getLongitude());
}
// Draw Points on MapView
map.addPolyline(new PolylineOptions()
.add(points)
.color(Color.parseColor("#009688"))
.width(5));
}
reference https://www.mapbox.com/android-sdk/examples/directions/
while loading google map on device i am receiving below screen sometimes.it comes on second load as shown below. otherwise it comes perfectly as normal google map with route I am using SupportmapFragment and get googleMap object as.
supportMapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map_view_fragment);
below is code for displaying map in activity/fragment
public static void drawRouteIntoMap(final List<? extends MapHelper> position, final GoogleMap googleMap) {
/*List<MapHelper> position = new ArrayList<MapHelper>();
for (int i = lastPosition; i < maps.size(); i++) {
position.add(maps.get(i));
}*/
final LatLngBounds.Builder mapBounds = new LatLngBounds.Builder();
if (position.size() > 0 && Validator.isNotNull(googleMap)) {
googleMap.clear();
List<PolylineOptions> polylineOptionses = new ArrayList<PolylineOptions>();
PolylineOptions option = null;
Boolean lastPause = null;
for (MapHelper map : position) {
if (map.isPause()) {
if (Validator.isNull(lastPause) || !lastPause) {
option = new PolylineOptions().width(5).color(Color.rgb(255, 0, 155)).geodesic(true);
polylineOptionses.add(option);
}
mapBounds.include(new LatLng(map.getLatitude(),map.getLongitude()));
option.add(new LatLng(map.getLatitude(), map.getLongitude()));
} else {
if (Validator.isNull(lastPause) || lastPause) {
option = new PolylineOptions().width(5).color(Color.rgb(0, 179, 253)).geodesic(true);
polylineOptionses.add(option);
}
mapBounds.include(new LatLng(map.getLatitude(),map.getLongitude()));
option.add(new LatLng(map.getLatitude(), map.getLongitude()));
}
lastPause = map.isPause();
}
for (PolylineOptions options : polylineOptionses) {
googleMap.addPolyline(options);
}
if(Validator.isNotNull(option)){
//List<LatLng> points = option.getPoints();
googleMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
#Override
public void onMapLoaded() {
LatLng startPoint = new LatLng(position.get(0).getLatitude(), position.get(0).getLongitude());
googleMap.addMarker(new MarkerOptions().position(startPoint).title("start").icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)));
mapBounds.include(startPoint);
LatLng endPoint = new LatLng(position.get(position.size() - 1).getLatitude(), position.get(position.size() - 1).getLongitude());
mapBounds.include(endPoint);
googleMap.addMarker(new MarkerOptions().position(endPoint).title("finish").icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)));
googleMap.setPadding(15, 205, 10, 110);
googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(mapBounds.build(), 0));
//googleMap.animateCamera(CameraUpdateFactory.newLatLngBounds(mapBounds.build(), 10));
googleMap.moveCamera(CameraUpdateFactory.zoomOut());
}
});
}
}
}
supportMapFragment.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap googleMap) {
if (Validator.isNotNull(googleMap)) {
googleMap.setMyLocationEnabled(false);
googleMap.clear();
googleMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
#Override
public void onMapClick(LatLng latLng) {
if (activity.preferences.isSaveScreen()) {
facebook.setChecked(false);
twitter.setChecked(false);
activity.replaceFragment(new FullMapFragment(), null);
}
if (!activity.preferences.isSaveScreen()) {
activity.preferences.setHistoryScreen(true);
activity.replaceFragment(new FullMapFragment(), null);
}
}
});
if (gps) {
nonGpsSummary.setVisibility(View.GONE);
List<HistoryMap> historyMaps = new ArrayList<HistoryMap>();
if (Validator.isNotNull(activity.preferences.getUserHistory().getHistoryMaps())) {
historyMaps.addAll(Arrays.asList(activity.preferences.getUserHistory().getHistoryMaps()));
}
if (historyMaps.size() > 0) {
if (Validator.isNotNull(googleMap)) {
drawRouteIntoMap(historyMaps, googleMap);
}
} else {
mapFrame.setVisibility(View.GONE);
}
} else {
gpsSummary.setVisibility(View.GONE);
}
}
}
});
this question is in relation with zoom over specific route google map.
by using that i get proper route with mapbounds but i m not getting why this screen is displaying.
i am not receiving cordinates 0.0 i debug that,api key is also proper.
You are calling moveCamera twice. The first one tries to move the camera but the second one doesn't wait for the first one to end and performs the zoom out.
This may not happen all the times and may behave differently on different devices.
The best option is to set a padding on your CameraUpdateFactory.newLatLngBounds(mapBounds.build(), 0) instead of 0
This problem occurs when your coordinates are not properly set. Make sure the coordinates that you are using is pointing in the land to get the maps correctly. Another possible reason is your API key is not working, try to generate new API key for this project.
For more information, check these related SO questions.
Android google maps return error and blue screen
Blue screen in Android Google Maps