In my Android application i need to get the traveled road with car and i check it with google android directions API and GPS.
But the problem is that some times the GPS location is not precise and i can get an error of 10Km for some lecture and that means that in a total travel of 150km my "distance traveled" can be 250km and it's wrong!
Yesterday i test it in highway and the problem is that when the marker is located out from highway, the calculation of distance traveled from my current position and the last marker located by road is very wrong (in this case out of the highway).
There is some best way for getting traveled distance with car using the phone?
Maybe some better code for getting more precise GPS position?
Here is my code:
private void getUserLocation() {
Log.d(TAG, "getUserLocation()");
checkLocationPermission();
mFusedLocationClient.getLastLocation()
.addOnSuccessListener(getActivity(), new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
// Got last known location. In some rare situations this can be null.
if (location != null) {
// Logic to handle location object
String stringStartLat, stringStartLng;
double lat = location.getLatitude();
double lng = location.getLongitude();
//Start position of device
if (travelInfo.getStartLat() == 0 && travelInfo.getStartLng() == 0) {
travelInfo.setStartLat(lat);
travelInfo.setStartLng(lng);
//Set lastcoordinates equals to start
travelInfo.setLastLat(lat);
travelInfo.setLastLng(lng);
}
//Current position of device
travelInfo.setCurrentLat(lat);
travelInfo.setCurrentLng(lng);
stringStartLat = Double.toString(travelInfo.getStartLat());
stringStartLng = Double.toString(travelInfo.getStartLng());
//Set the TextView in the fragment with start coordinates
Log.d(TAG,"LatitudeStart: " + stringStartLat);
Log.d(TAG,"LongitudeStart: " + stringStartLng);
if (startMarker == null) {
//Add the user location to the map with a marker
LatLng userLoction = new LatLng(travelInfo.getStartLat(), travelInfo.getStartLng());
startMarker = googleMap.addMarker(new MarkerOptions()
.position(userLoction)
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE))
.title("Start Position")
.snippet("Show the start position of user"));
// For zooming automatically to the location of the marker
CameraPosition cameraPosition = new CameraPosition.Builder().target(userLoction).zoom(9).build();
googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
} else {
LatLng currentLocation = new LatLng(travelInfo.getCurrentLat(), travelInfo.getCurrentLng());
currentPositionMarker = googleMap.addMarker(new MarkerOptions()
.position(currentLocation)
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_YELLOW))
.title("Current Position")
.snippet("Show the current position of user during travel"));
// For zooming automatically to the location of the marker
CameraPosition cameraPosition = new CameraPosition.Builder().target(currentLocation).zoom(11).build();
googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
if (travelInfo.getEndLat() != 0 && travelInfo.getEndLng() != 0) {
Log.i(TAG, "Dentro if userlocation");
//Get total distance of travel
getTotalDistanceTime(travelInfo);
//Get the percurred distance from last known coordinates
getPercurredDistance(travelInfo);
}
}
}
});
}
And getpercurredDistance use google direction API with this url
String url = "https://maps.googleapis.com/maps/api/directions/json?origin=" + obj.getLastLat() + "," + obj.getLastLng() + "&destination=" + obj.getCurrentLat() + "," + obj.getCurrentLng() + "&mode=driving&key=AI*******************I";
For getting distance traveled from last marker and current position marker.
But some times it put the localized position too far from real position... how avoid this?
EDIT
The method that i use is good for my work? mFusedLocationClient.getLastLocation()
There is no possibilities to get more precise GPS position from GPS sensor of android device, but you can filter "wrong" points this ways:
1) for each travel point get several values of Lat and Lng, discard the minimum and maximum and average the remaining ones;
2) log timestamps of each travel point and compare it for two neighboring points: speed (distance between that two points divided by time interval of that points) grater than max. car speed (e.g. 250 km/h) that means the second point is wrong (if first point is good of course).
3) use Google Maps Roads API to find best-fit road geometry for a given set of GPS coordinates.
Also take a look at this question.
For real-time location purposes, location updates allow you to request location updates at different intervals. See the android developer location documentation. The function you want is FusedLocationProviderClient.requestLocationUpdates.
There is no reason GPS (or any other widely used location technology) should ever give you 10km error for a single location estimate. If you are getting this, there is a large mismatch between when you the location estimate was made and when you are requesting it.
Related
How to Compare saved (in database ) Geo Location(Longitude and Latitude) with currently getting one using GPS.i tried following link but it doesn't work for me ,getting wrong output.Please help me i am new in Android.
How to use coarse location to compare with saved location in database
my requirement is exact as explained in ANS.
i did
float radius = 150; // distance in meter
double latitude_new= gps.getLatitude();
double longitude_new = gps.getLongitude();
Location location1= new Location("gpslocation");
location1.setLatitude(21.xxxxxxx);
location1.setLongitude(78.xxxxxxx);
Location location2= new Location("gpslocation");
location2.setLatitude(latitude_new);
location2.setLongitude(latitude_new);
float distance = location2.distanceTo(location1);
distance=Math.abs(distance);
//comparing two distance and radius
if (distance <= radius){
Toast.makeText(MyActivity.this, "At home", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(MyActivity.this,"Not in Home",Toast.LENGTH_SHORT).show();
}
problem is i m getting only "Not in Home" at SAME location which i have hard-coded and even on other locations(other than hard-coded).
thanks
You have provide latitude for the longitude also , edit your code as follows and try ,
location2.setLongitude(longitude_new);
Here i am able to display User on google map by getting user latitude and longitude now i want to display near by events happening in user location and want to display nearby venues so chosen foursquare api.here it is
2nd one
Here is my code to display user on map
R.id.map)).getMap();
// Creating location manager and location classes instances
locationManager = (LocationManager) this
.getSystemService(LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0,
0, this);
;
mCurrentLocation = locationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
// if location found display as a toast the current latitude and
// longitude
if (mCurrentLocation != null) {
Toast.makeText(
this,
"Current location:\nLatitude: "
+ mCurrentLocation.getLatitude() + "\n"
+ "Longitude: " + mCurrentLocation.getLongitude(),
Toast.LENGTH_LONG).show();
USER_LOCATION = new LatLng(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude());
// adding marker
googleMap.addMarker(new MarkerOptions().position(USER_LOCATION).icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ROSE)).title("Your current location"));
// Move the camera instantly to hamburg with a zoom of 15.
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(USER_LOCATION, 12));
// Zoom in, animating the camera.
googleMap.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null);
give me a brief idea how to use that api.based on my code.
Sorry, but do you want a complete tutorial for copy&paste?
You managed to get a location, you have a documentation of the api you want to use... so use it?
Take the location you have from Android. Format it so that the api can use it (perhaps they need coordinates, perhaps a city name, ...) and then call the web service. You will get a result and have to interpret it.
Where is actually your problem?
I'm wrinting a application and I have to show the distance covered while I'm running.
I use the function "public void onLocationChanged" of the LocationListener. When the user tap a botton and start running I want to show the distance he covered updated to the point in which he is located.
I've written this code:
public void onLocationChanged(Location location) {
if(location != null) {
if(location.hasSpeed()){
if(latitude1 == 0 && longitude1 == 0){
latitude1 = (location.getLatitude()*Math.PI)/180;
longitude1 = (location.getLongitude()*Math.PI)/180;
} else{
latitude2 = (location.getLatitude()*Math.PI)/180;
longitude2 = (location.getLongitude()*Math.PI)/180;
distance = (6372.795477598)*Math.acos(Math.sin(latitude1)
*Math.sin(latitude2)+Math.cos(latitude1)
*Math.cos(latitude2)*Math.cos(longitude1-longitude2));
sumDistance += distance;
latitude1 = latitude2;
longitude1 = longitude2;
}
tv.setText("Distance covered=" + sumDistance + " m");
}
}
}
Is it accurated?
Just a Suggestion:
Store the Latitude and Longitude of the start location and the end location when the user clicks the appropriate button.
and then you could use distanceBetween or distanceTo to get the distance between those two geoPoints.
P.S: This may not work if the user will start and end his run at the same point ;)
Addition:
Check this tutorial:
Recently google has improved its location based API's. They have fused the sensors with the location based api's to share examples of how location can be made more accurate (about 4 times more effective) and consume much lesser power (10 times lesser).
Some interesting links for you to go through will be this and video google io.
SO link for how to use the API's here
I am working with GPS related app. I need to get vertical accuracy but it always gets fix 11.0000. I need it to be dynamic as lat and lng. I have used getAccuracy but it results in horizontal accuracy.
#Override
public void onLocationChanged(Location location) {
if (location != null) {
lat = location.getLatitude();
lon = location.getLongitude();
Geocoder geoCoder = new Geocoder(getBaseContext(), Locale.getDefault());
address = mailOb.getAddress(geoCoder, lat, lon);
if (!meterFootFlag) {
diameter = Math.round(location.getAccuracy()) + " m.";
altitude = Math.round(location.getAltitude()) + " m.";
} else {
diameter = Math.round(location.getAccuracy() * 3.28084) + " ft.";
altitude = Math.round(location.getAltitude() * 3.28084) + " ft.";
}
if (diameter.contains("+"))
diameter.replace("+", "");
else if (altitude.contains("+"))
altitude.replace("+", "");
} else {
lat = 0.0;
lon = 0.0;
if (!meterFootFlag) {
altitude = 0.0 + " m.";
diameter = 0.0 + " m.";
} else {
altitude = 0.0 + " ft.";
diameter = 0.0 + " ft.";
}
}
mlocManager.removeUpdates(MySettings.this);
pDialog.dismiss();
}
How can I get vertical accuracy?
Thanks in advance
Android does not provide the vertical accuracy.
Vertical accuracy usually is 2-3 times worse then horizontal accuracy.
A simple solution: use the androids accuracy for both horizontal and vertical.
advanced solution 1: find out what android uses as total accuracy (it could be a radial error of an error-sphere, including lat,long and altitude)
try to find out a conversion factor, e.g take accuracy and multiply *2,5
Another solution, look at iphone horizontal and vert accuracy, and compare to that of android. find out an average conversion factor from acc to vert acc.
Solution 3: think why you need vertical accuracy at all. why do you need that?
hints:examples from my iphone4: when iphone shows 30m hor, i have 57vert, 10hor: 15-20vert, 5 hor: 10vert
Starting with API 26 you can use getVerticalAccuracyMeters() method
#Override
#RequiresApi(Build.VERSION_CODES.O)
public void onLocationChanged(Location location) {
float accuracy = location.getVerticalAccuracyMeters();
}
Altitude accuracy heavily depends on core GPS accuracy, use of additional sensors as barometer and use of wifi/cell networks plus the fusion algorithms. It is NOT have a constant ratio. If u really want to get accuracy you can try the following: check variance of the signal while motionless, this will not always work as some devices will detect motionless and just repeat last output to save power. Another approach which is bit costly is to check with reference as https://developers.google.com/maps/documentation/elevation/intro
so u basically take lat lon measurement with the lat lon error and check the vertical error u get assuming you are in open area.
I am building a GPS Android application whereby it retrieves the nearest places based on the user's current location. At first, I detect both GPS and network to see if they are enabled. If both are enabled I would use GPS first because it is the most accurate, and for my application it is safe to assume they are outside, therefore, retrieving GPS should not take too long. Nevertheless, there are always situations when GPS takes a long time. How do I therefore implement a way to switch over to NETWORK_PROVIDER if GPS takes over, for example, 2 minutes?
This is my code right now:
I check if GPS or internet is enabled.
if(!GPSEnabled && !networkEnabled)
{
Toast.makeText(this, "Error: This application requires a GPS or network connection",
Toast.LENGTH_SHORT).show();
}
else
{
if(GPSEnabled)
{
locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
}
else if(networkEnabled)
{
System.out.println("Getting updates from network provider");
locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
}
}
This is the onLocationChanged method. I get the lat/lng values and then send them off to my server and then do appropriate stuff with it.
public void onLocationChanged(Location location)
{
//Get coordinates
double lat = (location.getLatitude());
double lng = (location.getLongitude());
Log.d("MainActivity", "got location: " + lat + ": " + lng);
//get nearest locations
new GetLocations().execute(SharedVariables.root + SharedVariables.locationsController + SharedVariables.getNearestMethod + lat + "/" + lng);
// Zoom in, animating the camera after the markers have been placed
map.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lng), 10));
System.out.println("lat = " + lat + ", lng = " + lng);
//Stop listening for updates. We only want to do this once.
locManager.removeUpdates(this);
}
What would I need to add to switch over to Network or GPS if either one takes too long?
I'd recommend to use both providers at the same time and determine more accurate location using, for example, isBetterLocation() function from this article: http://developer.android.com/guide/topics/location/strategies.html. In this case users won't have to wait 2 minutes to use your app, if GPS is slow. At first, you'll use network updates, and then, when GPS fixes are obtained, more accurate locations.