So I'm making an app and I need continuous location updates to move my custom location marker. I wanted to have a smooth marker movement like Uber has. I implemented SmartLocation library using FusedLocationProvider, location accuracy is set to HIGH, and location is updated every second, yet for some reason I'm getting slow updates that are not accurate. Can someone tell me what I'm doing wrong?
public void onLocationUpdatedListenerInit(){
onLocationUpdatedListener=new OnLocationUpdatedListener() {
#Override
public void onLocationUpdated(Location location) {
animateMarker(location, myLocation);
}
};
}
public void startingLocationTracking(){
LocationParams.Builder builder = new LocationParams.Builder().setAccuracy(LocationAccuracy.HIGH)
.setDistance(0)
.setInterval(1000);
SmartLocation.with(this).location(new LocationGooglePlayServicesProvider()).continuous().config(builder.build()).start(onLocationUpdatedListener);
}
AnimateMarker method:
public static void animateMarker(final Location destination, final Marker marker) {
if (marker != null) {
final LatLng startPosition = marker.getPosition();
final LatLng endPosition = new LatLng(destination.getLatitude(), destination.getLongitude());
final float startRotation = marker.getRotation();
final LatLngInterpolator latLngInterpolator = new LatLngInterpolator.LinearFixed();
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.setDuration(1000); // duration 1 second
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override public void onAnimationUpdate(ValueAnimator animation) {
try {
float v = animation.getAnimatedFraction();
LatLng newPosition = latLngInterpolator.interpolate(v, startPosition, endPosition);
marker.setPosition(newPosition);
marker.setRotation(computeRotation(v, startRotation, destination.getBearing()));
} catch (Exception ex) {
// I don't care atm..
}
}
});
valueAnimator.start();
}
}
Related
my marker is moving smoothly but polyline will be create suddenly after car marekr moved or before car marker moved. How to resolve this problem. I want to draw polyline when my car marker will be moving. I was tried to create polyline when car marker moving using ValueAnimator class. But its not implemented. and unable to set duration in polyline.
// My polyline code
if (polyline != null)
{
polyline.remove();
}
if(coordinateList.size()>3)
{
//animate here...
PolylineOptions polyOptions = new PolylineOptions();
List<LatLng> latLngList = new ArrayList<>(coordinateList);
polyOptions.color(ContextCompat.getColor(getApplicationContext(),
R.color.green_poly));
polyOptions.addAll(latLngList);
polyOptions.startCap(new ButtCap());
polyOptions.width(12);
polyOptions.jointType(JointType.ROUND);
polyOptions.pattern(PATTERN_POLYGON_ALPHA);
polyline = mMap.addPolyline(polyOptions);
removeLine = true;
}
//my car moving animation code
CarMoveAnimation.startcarAnimation(zoomLevel,marker, mMap, new
LatLng(coordinateList.get(coordinateList.size() - 2).latitude,
coordinateList.get(coordinateList.size() -
2).longitude),
new LatLng(coordinateList.get(coordinateList.size() -
1).latitude,
coordinateList.get(coordinateList.size() -
1).longitude), duration, bearing,
new GoogleMap.CancelableCallback() {
#Override
public void onFinish() {
Log.v("Done","value"+"");
}
#Override
public void onCancel() {
Log.v("Done","value"+"");
}
});
checkPoly = true;
createPolyLine();
}
//This is my CarMoveAnimation.java code
public class CarMoveAnimation {
public CarMoveAnimation() {
}
public static void startcarAnimation(final float zoom,final Marker carMarker, final GoogleMap
googleMap, final LatLng startPosition,
final LatLng endPosition, int duration, float bearing,
final GoogleMap.CancelableCallback callback) {
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.0F, 1.0F);
if (duration < 3000) {
duration = 3000;
}
valueAnimator.setDuration((long)duration);
final CarMoveAnimation.LatLngInterpolatorNew latLngInterpolator = new
CarMoveAnimation.LatLngInterpolatorNew.LinearFixed();
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float v = valueAnimator.getAnimatedFraction();
double var10000 = (double)v * endPosition.longitude + (double)(1.0F - v) *
startPosition.longitude;
var10000 = (double)v * endPosition.latitude + (double)(1.0F - v) *
startPosition.latitude;
LatLng newPos = latLngInterpolator.interpolate(v, startPosition, endPosition);
carMarker.setPosition(newPos);
carMarker.setAnchor(0.5F, 0.5F);
carMarker.setRotation((float) bearing);
if (callback != null) {
googleMap.animateCamera(CameraUpdateFactory.newCameraPosition((new
Builder()).target(newPos).bearing((float) bearing).zoom(zoom).build()), callback);
} else {
googleMap.animateCamera(CameraUpdateFactory.newCameraPosition((new
Builder()).target(newPos).bearing((float)bearing ).zoom(zoom).build()));
//CarMoveAnimation.bearingBetweenLocations(startPosition, endPosition)
}
}
});
valueAnimator.start();
}
public interface LatLngInterpolatorNew {
LatLng interpolate(float var1, LatLng var2, LatLng var3);
public static class LinearFixed implements CarMoveAnimation.LatLngInterpolatorNew {
public LinearFixed() {
}
public LatLng interpolate(float fraction, LatLng a, LatLng b) {
double lat = (b.latitude - a.latitude) * (double)fraction + a.latitude;
double lngDelta = b.longitude - a.longitude;
if (Math.abs(lngDelta) > 180.0D) {
lngDelta -= Math.signum(lngDelta) * 360.0D;
}
double lng = lngDelta * (double)fraction + a.longitude;
return new LatLng(lat, lng);
}
}
}
}
Actually I am getting the latitude and longitude value from the ArrayList, and I want to show these location on map in the interval of 3 seconds.
I have created a method named waitSec() and I'm calling it in displayLocation() but this is not working because this blocked the main thread so I used handler and asynctask and I found difficulties in this.
public void waitSec(){
long start = System.currentTimeMillis();
while(System.currentTimeMillis()<start+3000);
}
class MyAsyncTask extends AsyncTask<Integer,Integer,Void>{
#Override
protected Void doInBackground(Integer... integers) {
waitSec();
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Log.e("TAG", "onPostExecute: we have waited 3 seconds" );
displayCurrentLocation();
}
}
private void displayCurrentLocation() {
for(int i=0;i<trackObjectList.size();i++){
//Log.e("TAG", "displayCurrentLocation: "+trackObjectList.get(i).getLatitude() );
if(trackObjectList.size()>0)
latLng = new LatLng(Double.parseDouble(trackObjectList.get(i).getLatitude())
,Double.parseDouble(trackObjectList.get(i).getLongitude()));
mMap.addMarker(new MarkerOptions().position(latLng)
.title("Here")
.icon(BitmapDescriptorFactory.fromBitmap(getSmallerSize(R.drawable.green_dot_th))));
mMap.animateCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng,15f));
//waitSec();
}
}
I expected that after every 2-3 seconds the markers will add on google map but it is not adding in this interval. It shows all the latlng marks on google map.
You can easily achieve this using RxJava
Observable.from(listOfItems)
.zipWith(Observable.interval(2, TimeUnit.SECONDS), (item, notUsed) -> item)
.subscribe(
// add marker addition logic here
);
You need to animate your marker when create--
private void animateMarker(final Marker marker) {
final Handler handler = new Handler();
final long startTime = SystemClock.uptimeMillis();
final long duration = 300; // ms
Projection proj = mMap.getProjection();
final LatLng markerLatLng = marker.getPosition();
Point startPoint = proj.toScreenLocation(markerLatLng);
startPoint.offset(0, -10);
final LatLng startLatLng = proj.fromScreenLocation(startPoint);
final Interpolator interpolator = new BounceInterpolator();
handler.post(new Runnable() {
#Override
public void run() {
long elapsed = SystemClock.uptimeMillis() - startTime;
float t = interpolator.getInterpolation((float) elapsed / duration);
double lng = t * markerLatLng.longitude + (1 - t) * startLatLng.longitude;
double lat = t * markerLatLng.latitude + (1 - t) * startLatLng.latitude;
marker.setPosition(new LatLng(lat, lng));
if (t < 1.0) {
// Post again 16ms later (60fps)
handler.postDelayed(this, 16);
}
}
});
}
you have a for loop in displayCurrentLocation which is displaying everything everytime the asyncTask.onPostExecute() runs.
try the following:
private int objectsSize = trackObjectList.size()-1;//initialise this somewhere appropriate
private void displayCurrentLocation()
{
int i=objectsSize--;
//Log.e("TAG", "displayCurrentLocation: "+trackObjectList.get(i).getLatitude() );
if(i>=0)
{
latLng = new LatLng(Double.parseDouble(trackObjectList.get(i).getLatitude())
,Double.parseDouble(trackObjectList.get(i).getLongitude()));
mMap.addMarker(new MarkerOptions().position(latLng)
.title("Here")
.icon(BitmapDescriptorFactory.fromBitmap(getSmallerSize(R.drawable.green_dot_th))));
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng,15f));
}
}
In my application needs to display a smooth "move" google maps marker from one point to another.
I use the following method for the animation:
public void animateMarker(final Marker marker, final LatLng toPosition,
final boolean hideMarker) {
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
Projection proj = mMap.getProjection();
Point startPoint = proj.toScreenLocation(marker.getPosition());
final LatLng startLatLng = proj.fromScreenLocation(startPoint);
final long duration = 500;
final Interpolator interpolator = new LinearInterpolator();
handler.post(new Runnable() {
#Override
public void run() {
long elapsed = SystemClock.uptimeMillis() - start;
float t = interpolator.getInterpolation((float) elapsed
/ duration);
double lng = t * toPosition.longitude + (1 - t)
* startLatLng.longitude;
double lat = t * toPosition.latitude + (1 - t)
* startLatLng.latitude;
marker.setPosition(new LatLng(lat, lng));
if (t < 1.0) {
// Post again 16ms later.
handler.postDelayed(this, 16);
} else {
if (hideMarker) {
marker.setVisible(false);
} else {
marker.setVisible(true);
}
}
}
});
}
But as a result of simply creating a new marker to the new location (though old is not removed):
I copied some of the code from the project mentioned in the official video.
I tried to reproduce it with this code and this seems to be working for me, so hopefully my code would help you, even for a bit.
static final LatLng SomePos = new LatLng(37.7796354, -122.4159606);
try {
if (googleMap == null) {
googleMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
}
googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
googleMap.setMyLocationEnabled(true);
googleMap.setTrafficEnabled(false);
googleMap.setIndoorEnabled(false);
googleMap.setBuildingsEnabled(true);
googleMap.getUiSettings().setZoomControlsEnabled(true);
googleMap.moveCamera(CameraUpdateFactory.newLatLng(SomePos));
googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder()
.target(googleMap.getCameraPosition().target)
.zoom(17)
.bearing(30)
.tilt(45)
.build()));
myMarker = googleMap.addMarker(new MarkerOptions()
.position(SomePos)
.icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_launcher))
.title("Hello world"));
googleMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener()
{
#Override
public boolean onMarkerClick(Marker arg0) {
final LatLng startPosition = myMarker.getPosition();
final LatLng finalPosition = new LatLng(37.7801569,-122.4148528);
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
final Interpolator interpolator = new AccelerateDecelerateInterpolator();
final float durationInMs = 3000;
final boolean hideMarker = false;
handler.post(new Runnable() {
long elapsed;
float t;
float v;
#Override
public void run() {
// Calculate progress using interpolator
elapsed = SystemClock.uptimeMillis() - start;
t = elapsed / durationInMs;
v = interpolator.getInterpolation(t);
LatLng currentPosition = new LatLng(
startPosition.latitude*(1-t)+finalPosition.latitude*t,
startPosition.longitude*(1-t)+finalPosition.longitude*t);
myMarker.setPosition(currentPosition);
// Repeat till progress is complete.
if (t < 1) {
// Post again 16ms later.
handler.postDelayed(this, 16);
} else {
if (hideMarker) {
myMarker.setVisible(false);
} else {
myMarker.setVisible(true);
}
}
}
});
return true;
}
});
} catch (Exception e) {
e.printStackTrace();
}
I know this is an old question but...
You can use value interpolator for this task :
fun changePositionSmoothly(marker:Marker?, newLatLng: LatLng){
if(marker == null){
return;
}
val animation = ValueAnimator.ofFloat(0f, 100f)
var previousStep = 0f
val deltaLatitude = newLatLng.latitude - marker.position.latitude
val deltaLongitude = newLatLng.longitude - marker.position.longitude
animation.setDuration(1500)
animation.addUpdateListener { updatedAnimation ->
val deltaStep = updatedAnimation.getAnimatedValue() as Float - previousStep
previousStep = updatedAnimation.getAnimatedValue() as Float
marker.position = LatLng(marker.position.latitude + deltaLatitude * deltaStep * 1/100, marker.position.longitude + deltaStep * deltaLongitude * 1/100)
}
animation.start()
}
In Java
void changePositionSmoothly(Marker marker, LatLng newLatLng) {
if (marker == null) {
return;
}
ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
final float[] previousStep = {0f};
double deltaLatitude = newLatLng.latitude - marker.getPosition().latitude;
double deltaLongitude = newLatLng.longitude - marker.getPosition().longitude;
animation.setDuration(1500);
animation.addUpdateListener(animation1 -> {
float deltaStep = (Float) animation1.getAnimatedValue() - previousStep[0];
previousStep[0] = (Float) animation1.getAnimatedValue();
marker.setPosition(new LatLng(marker.getPosition().latitude + deltaLatitude * deltaStep * 1 / 100, marker.getPosition().longitude + deltaStep * deltaLongitude * 1 / 100));
});
animation.start();
}
To prevent error accumulation, at the end of the animation you can set the new position, but this is enough for most cases.
First of all I am new to android and JAVA and as registered user of stackoverflow, but it helped me many times to find a good answer so, thank you for this community, got me many times out of mud with my school projects
I am here because I'm stuck in this small project, is an university one so no money involved.
I am trying to get a route displayed and update it as I move through the city using android google maps api. Until now I managed to get my location, and I can display a route between two points, but the problem is when I want to have the starting point from my current location, it seems I can't save it to a variable (or I don't know how) I used google example for map display as base.
I will post the entire code, maybe someone can also find it useful. Since is an university small project I don't have secrets to hide and I am here to learn so is nice to post the full code.
If someone has a hint for my problem I would appreciate. Thank you!
NOTE: the problem is getting this baby displaying the route from my current location to the second location that is a fixed one.
The main code is the following:
public class mapDisplay extends ActionBarMapActivity {
private LocationManager myLocationManager;
private LocationListener myLocationListener;
private MapController myMapController;
private MapView myMapView;
private MyLocationOverlay myLocation;
private void CenterLocatio(GeoPoint centerGeoPoint)
{
myMapController.animateTo(centerGeoPoint);
};
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.map_screen);
myMapView = (MapView) findViewById(R.id.mapview);
//mapView.setBuiltInZoomControls(true);
myMapView.setSatellite(false); //Set satellite view
myMapController = myMapView.getController();
myMapController.setZoom(15); //Fixed Zoom Level
myLocationManager = (LocationManager)getSystemService(
Context.LOCATION_SERVICE);
//For enable location services dialogue
if (!myLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
createGpsDisabledAlert();
}
// see createGpsDisabledAlert function below
myLocationListener = new MyLocationListener();
myLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
0,
0,
myLocationListener);
//Get the current location in start-up
GeoPoint initGeoPoint = new GeoPoint(
(int)(myLocationManager.getLastKnownLocation(
LocationManager.GPS_PROVIDER)
.getLatitude()*1000000),
(int)(myLocationManager.getLastKnownLocation(
LocationManager.GPS_PROVIDER)
.getLongitude()*1000000));
CenterLocatio(initGeoPoint);
//draw the sample route
MapView mv = (MapView) findViewById(R.id.mapview);
mv.setBuiltInZoomControls(true);
MapController mc = mv.getController();
ArrayList all_geo_points = getDirections(50.0536, 8.69339, 50.021973, 8.69584);
GeoPoint moveTo = (GeoPoint) all_geo_points.get(0);
mc.animateTo(moveTo);
mc.setZoom(12);
mv.getOverlays().add(new MyOverlay(all_geo_points));
//Adding position icon for current location
// Add the MyLocationOverlay
myLocation = new MyLocationOverlay(this, myMapView);
myMapView.getOverlays().add(myLocation);
myLocation.enableMyLocation();
myLocation.runOnFirstFix(new Runnable() {
public void run() {
myMapController.animateTo(myLocation.getMyLocation());
}
});
}
private class MyLocationListener implements LocationListener{
public void onLocationChanged(Location argLocation) {
// TODO Auto-generated method stub
GeoPoint myGeoPoint = new GeoPoint(
(int)(argLocation.getLatitude()*1000000),
(int)(argLocation.getLongitude()*1000000));
CenterLocatio(myGeoPoint);
}
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
//toast shown if GPS is disabled
Context context = getApplicationContext();
CharSequence text = "GPS is disabled! If you want to take full advantage of map please enable the GPS!";
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
public void onStatusChanged(String provider,
int status, Bundle extras) {
// TODO Auto-generated method stub
}
}
#Override
protected void onResume() {
super.onResume();
myLocation.enableMyLocation();
}
#Override
protected void onPause() {
super.onPause();
myLocation.disableMyLocation();
}
//Back button press returns to first activity (selection screen)
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
//super.onBackPressed();
}
#Override
protected boolean isRouteDisplayed() {
return false;
}
//rest of functions for GPS alert
private void createGpsDisabledAlert(){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Your GPS is disabled! Would you like to enable it?")
.setCancelable(false)
.setPositiveButton("Enable GPS",
new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int id){
showGpsOptions();
}
});
builder.setNegativeButton("Do nothing",
new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int id){
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
}
private void showGpsOptions(){
Intent gpsOptionsIntent = new Intent(
android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(gpsOptionsIntent);
}
//Testing - directions
public static ArrayList getDirections(double lat1, double lon1, double lat2, double lon2) {
String url = "http://maps.googleapis.com/maps/api/directions/xml?origin=" +lat1 + "," + lon1 + "&destination=" + lat2 + "," + lon2 + "&sensor=false&units=metric";
String tag[] = { "lat", "lng" };
ArrayList list_of_geopoints = new ArrayList();
HttpResponse response = null;
try {
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpPost httpPost = new HttpPost(url);
response = httpClient.execute(httpPost, localContext);
InputStream in = response.getEntity().getContent();
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = builder.parse(in);
if (doc != null) {
NodeList nl1, nl2;
nl1 = doc.getElementsByTagName(tag[0]);
nl2 = doc.getElementsByTagName(tag[1]);
if (nl1.getLength() > 0) {
list_of_geopoints = new ArrayList();
for (int i = 0; i < nl1.getLength(); i++) {
Node node1 = nl1.item(i);
Node node2 = nl2.item(i);
double lat = Double.parseDouble(node1.getTextContent());
double lng = Double.parseDouble(node2.getTextContent());
list_of_geopoints.add(new GeoPoint((int) (lat * 1E6), (int) (lng * 1E6)));
}
} else {
// No points found
}
}
} catch (Exception e) {
e.printStackTrace();
}
return list_of_geopoints;
}}
EDIT 10.07.2012: I start to wonder if is a stupid question, no one knows the answer or no one wants to answer.
I have tried to save into local variables and use them in get Directions() function but for some reason is crashing my app. Or better, I am invited to fix the error before compiling.
I need to perform some tasks with google map,
1. first I need the user to be able to place only one marker
2. Then retrieve the city and other details such as street address
Does anyone know about this?
I wrote a minimal example to show how you could achieve what you're looking for:
public void onModuleLoad() {
RootPanel.get().add(new GoogleMaps());
}
private class GoogleMaps extends Composite {
private MapWidget fMap;
private Geocoder fCoder;
private Marker fMarker;
public GoogleMaps() {
fMap = new MapWidget(LatLng.newInstance(47.0559084, 8.3114878), 6);
fMap.setSize("300px", "300px");
fCoder = new Geocoder();
MarkerOptions options = MarkerOptions.newInstance();
options.setDraggable(true);
fMarker = new Marker(LatLng.newInstance(47.0559084, 8.3114878), options);
fMap.addOverlay(fMarker);
fMarker.setVisible(false);
addHandlers();
initWidget(fMap);
}
private void addHandlers() {
fMap.addMapDoubleClickHandler(new MapDoubleClickHandler() {
#Override
public void onDoubleClick(MapDoubleClickEvent event) {
if (event.getLatLng() != null) {
performReverseLookup(event.getLatLng());
}
}
});
fMarker.addMarkerDragEndHandler(new MarkerDragEndHandler() {
#Override
public void onDragEnd(MarkerDragEndEvent event) {
LatLng point = event.getSender().getLatLng();
if (point != null) {
performReverseLookup(point);
}
}
});
}
private void performReverseLookup(final LatLng point) {
fCoder.getLocations(point, new LocationCallback() {
#Override
public void onSuccess(JsArray<Placemark> locations) {
if (locations.length() > 0) {
LatLng point = locations.get(0).getPoint();
fMarker.setLatLng(point);
fMarker.setVisible(true);
fMap.getInfoWindow().open(point, new InfoWindowContent(locations.get(0).getAddress()));
}
}
#Override
public void onFailure(int statusCode) {}
});
}
}
To your first point: Create only one instance of Marker and update its LatLng upon user interaction (done in performReverseLookup()).
Your second question: After performing the reverse lookup you can get the Placemark object out of the locations array and retrieve details like the address.