Currently I am working on an application, where I want to calculate distance a vehicle travels. My requirement is while driving car, my Android device should calculate total distance I traveled and send this information to server. In order to do this, I used Android's location manager api, set criteria and used getBestProvider. This way we can either use GPS or Network to get latitude and longitude. The following is the code snippet of this:
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setPowerRequirement(Criteria.POWER_HIGH);
provider = locationManager.getBestProvider(criteria, false);
locationManager.requestLocationUpdates(provider,30000,5, this);
onLocationChanged() call back method provide latitude and longitude every time. We always store previous coordinates and when we get new coordinates we find the distance between the two using distanceBetween() api. The following is the code snippet of this:
public void onLocationChanged(Location location) {
findLatLongDistance(location);
}
private void findLatLongDistance(Location location) {
// TODO Auto-generated method stub
try{
Date date = new Date();
TimeStamp2 = sdf.format(date);
getSavedLatLong();//get lat and long from preference
Location locationB = new Location("point B");
locationB.setLatitude(location.getLatitude());
locationB.setLongitude(location.getLongitude());
Location locationA = new Location("point A");
locationA.setLatitude(prelat_val); //lat from pref locationA.setLongitude(prelong_val); //long from pref
if(prelat_val>0.0 && prelong_val>0.0){
Toast.makeText(LocationService.this,"Location Odometer Sum "+odometer_sum, Toast.LENGTH_LONG).show();
float distance2 = getDistance(prelat_val,prelong_val,location.getLatitude(),location.getLongitude());
odometer_sum = odometer_sum + (distance2/1000);
Toast.makeText(LocationService.this,"Lat "+prelat_val+"Long "+prelong_val+"Sum "+odometer_sum, Toast.LENGTH_LONG).show();
}
saveData(lat,lng,odometer_sum);
}catch(Exception e){
e.printStackTrace();
}
}
public float getDistance(double d, double e, double f, double g) {
float [] dist = new float[2];
Location.distanceBetween(d,e,f, g, dist);
return dist[0] ;
}
This is the list of issue that we face here:
The location it provide is not accurate. There is a difference of about 300-400 metres while we testing this app in 5 km distance
When the mobile is in same location for long time, it always provide different latitude and longitude. If you check above code snippet, in requestLocationUpdates(), we are setting 30 seconds time interval and 5m distance. Here what we thought is, if my mobile device move 5m distance AND if it cross 30 seconds interval, it will provide new latitude and longitude. But what really happens is, it provide coordinates every 30 seconds irrespective of device movement. I am not sure how to fix this issue.
While device is moving, how to get accurate value. Do I need to do some more things in the code?
I really spend so many hours trying various options. But I feel I am missing something here. Please help me on this. Thanks in advance..
Thanks,
Your minTime value in requestLocationUpdates() is 30seconds. Thats too long for an app that tries to calculate accurate distances. I have used locationManager.requestLocationUpdates(provider, 0, 5, locationListener);
in my code for long and I get accurate updates. Though this drains the battery very fast. So you would have to try different values to strike a balance between accuracy and battery life and see what suits your app
Related
i am trying to work on application , in which i have List of location from database and i want to check Which location from database is near to my current location within few miles like 20 miles and list got refreshed automatically with the refined Location and then send notification to user that you have enter to this location...
I have searched over this and come to know about Geofencing But i did not get it properly.. so please suggest me how should i start working on it ... Any sample , code or link will be helpful
thanks in advance
I have used one function distanceTo to calculate distance between to Locations.
I have coded it for only 100 mtr, you need to change value of distance you want to compare with.
private boolean isMarkerIn100(ArrayList<Model> arrayList) {
Location locationA = new Location("LocationA");
locationA.setLatitude(latitude);
locationA.setLongitude(longitude);
for (int i = 0; i < arrayList.size(); i++) {
Location locationB = new Location("LocationB");
locationB.setLatitude(arrayList.get(i).getLat());
locationB.setLongitude(arrayList.get(i).getLng());
if (locationA.distanceTo(locationB) < 100 && arrayList.get(i).getHit() > 4) {
return false;
}
}
return true;
}
In above code, latitude and longitude are for my (User's) location (Say locationA) and ArrayList is data from database with lat and lng.
In my application I want latitude and longitude value by GPS and/ or Network. My code work but some time it give accurate value some time it not give the accurate value, some time it give the value which is 10 or 20 meter far from the accurate place.
Code:
mlocListener = new MyLocationListener(getApplicationContext());
/* Use the LocationManager class to obtain GPS locations */
LocationManager mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (mlocManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
10000, 0, mlocListener);
} else if (mlocManager
.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
mlocManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 10000, 0, mlocListener);
}
Location gpsLocation = mlocManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
Location netLocation = mlocManager
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (gpsLocation != null) {
mlocListener.latitude = gpsLocation.getLatitude();
mlocListener.longitude = gpsLocation.getLongitude();
double lat = (double) (gpsLocation.getLatitude());
double lng = (double) (gpsLocation.getLongitude());
Toast.makeText(this, "Location attributes using GPS Provider",
Toast.LENGTH_LONG).show();
} else if (netLocation != null) {
mlocListener.latitude = netLocation.getLatitude();
mlocListener.longitude = netLocation.getLongitude();
double lat = (double) (netLocation.getLatitude());
double lng = (double) (netLocation.getLongitude());
Toast.makeText(this, "Location attributes using NETWORK Provider",
Toast.LENGTH_SHORT).show();
}
Use loc.getAccuracy() method to check the accuracy level of location you received. If the value is less then 10(or less than that) then you can consider it , otherwise wait for location Lister to fetch another location.
getLastKnownLocation is your last known location, dont use just getAccuracy also check the time.
Better dont use getLastKnownLocation if you need only accurate location.
Usually GPS is accurate upto 3m but if its 10 to 20 meters, it is something possible with GPS.
A standard GPS receiver for civil use offers an accuracy down to a few
meters. In praxis the number and geometry of the received satellites
influences the accuracy considerably, and in daily use, accuracies of
about 20 m can be expected.
GPS Accuracy
Also if you are getting your current location from network provider, you may expect even more inaccurate locations.
If you are looking forward to get maximum accuracy, I will say that you dismiss network provider because it is influenced by other factors related to phone operator etc.
locManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
This get your location using your phone internal GPSreceiver (time costly) but it gives you the maximum possible accuracy.
I used the following code to find the longitude and latitude for my android application
public double[] getlocation() {
LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
List<String> providers = lm.getProviders(true);
Location l = null;
for (int i = 0; i < providers.size(); i++) {
l = lm.getLastKnownLocation(providers.get(i));
if (l != null)
break;
}
double[] gps = new double[2];
if (l != null) {
gps[0] = l.getLatitude();
gps[1] = l.getLongitude();
}
return gps;
}
I got the accurate or exact latitude and longitude first time when i run the application after i tried to get the new co-ordinates from one miles away from my first location but i got the same latitude and longitude.
so please can you suggest me how this problem occurs. what is the solution for this ?
.getLastKnownLocation() will be inaccurate. You need to use a LocationListener to get accurate and up to date location updates. See this link. You generally ONLY want to use getLastKnownLocation ONCE upon starting to get a quick fix, then register a LocationListener to get more accurate, constant updates.
Also be aware that sitting in your house attempting to test will not work very well. You might need to go outside and walk around some.
i m using lat/lng to find where is my user and calculate the distance between him and another place in the map(its lat/lng is static).In order to do this i use :
private void findloc() {
// TODO Auto-generated method stub
try{
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
provider = locationManager.getBestProvider(criteria, false);
Location location = locationManager.getLastKnownLocation(provider);
Double lat = Double.valueOf(location.getLatitude());
Double lng = Double.valueOf(location.getLongitude());
Location location2 = new Location("gps");
location2.setLatitude(35.519583);
location2.setLongitude(24.016864);
float distance = location2.distanceTo(location);
TextView sitesdistancekm = (TextView) findViewById(R.id.sitesdistancekm);
sitesdistancekm.setText("Geographical Distance : "+distance/1000+" km");
Toast.makeText(otto.this, "lat: "+lat+"\nlng: "+lng,
Toast.LENGTH_LONG).show();
}
catch(Exception e){
TextView sitesdistancekm = (TextView) findViewById(R.id.sitesdistancekm);
sitesdistancekm.setText("No GPS signal");
}
}
My problem is that sometimes the location stacks and i m getting a wrong distance .i m calling findloc() as a refresh for the menu but it doesnt changes.
public boolean onOptionsItemSelected(MenuItem item) {
findloc();
return true;
}
Is there any way to improve it?Any idea please??
EDIT
Is that gonna work?
private void findloc() {
// TODO Auto-generated method stub
try{
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
provider = locationManager.getBestProvider(criteria, false);
Location location = locationManager.getLastKnownLocation(provider);
Double lat = Double.valueOf(location.getLatitude());
Double lng = Double.valueOf(location.getLongitude());
location2 = new Location("gps");
location2.setLatitude(35.519583);
location2.setLongitude(24.016864);
float distance = location2.distanceTo(location);
TextView sitesdistancekm = (TextView) findViewById(R.id.sitesdistancekm);
sitesdistancekm.setText("Geographical Distance : "+distance/1000+" km");
Toast.makeText(otto.this, "lat: "+lat+"\nlng: "+lng,
Toast.LENGTH_LONG).show();
onLocationChanged(location);
}
catch(Exception e){
TextView sitesdistancekm = (TextView) findViewById(R.id.sitesdistancekm);
sitesdistancekm.setText("No GPS signal");
}
}
private void onLocationChanged(Location location) {
// TODO Auto-generated method st
float distance = location2.distanceTo(location);
TextView sitesdistancekm = (TextView) findViewById(R.id.sitesdistancekm);
sitesdistancekm.setText("Geographical Distance : "+distance/1000+" km");
}
I've found that getLastKnownLocation() is not as reliable as registering a location listener. See this post for good information on how to implement one.
getLastKnownLocation docs state:
Returns a Location indicating the data from the last known location
fix obtained from the given provider. This can be done without
starting the provider. Note that this location could be out-of-date,
for example if the device was turned off and moved to another
location.
For me, I use getLastKnownLocation() to get an initial location, but then register a listener for anything else.
Referring to answer by Jack, getLastKnownLocation should not be used as sole measure of location detection. You need to divide your location detection logic to several steps:
Get the best provider you have for detailed accuracy
LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
// you need to specify the criteria here
criteria.setAccuracy(Criteria.ACCURACY_FINE);
String bestProvider = lm.getBestProvider(criteria, true);
However you cannot just use last known position as is. You need to check what is the last time the this location get fixed. Depending on the sensitivity that you need, you could check for elapsed time anywhere between 30 seconds to 5 minutes.
Location locate = lm.getLastKnownLocation(bestProvider);
if(System.currentTimeMillis() - locate.getTime() < TIME_TO_EXPIRE) {
// this is a valid location, let's use this location
// as the last time the provider check is within reasonable boundary
}
If the last known update has passed your boundary of expected time, you could assume the location is too old (the user has moved to different place) and needs to be updated. The next step for you is to request for location update by calling the following
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,
MIN_TIME, MIN_DISTANCE, locationListener);
As you can see, you don't call onLocationChange manually, but rather let the provider calls the listener if MIN_TIME and MIN_DISTANCE have been exceeded.
Note that if your position hasn't changed then onLocationChanged() will not get called. If certain period has passed without onLocationChanged getting called, you can assume your last known position is the most accurate one and you should use it.
There is also chance that the onLocationChanged() doesn't get called because the provider can't get a fix for your position. In this case, optionally, you could call other provide to see if they could provide you with location update before relying back on last known position
This is maybe a noob question but im not 100% sure about it.
How can i make a Location Object using Geo points? I want to use it to get the distance between two points.
I already found a thread where it says
Location loc1 = new Location("Location");
loc.setLatitude(geoPoint.getLatitudeE6);
loc.setLongitude(geoPoint.getLongitudeE6);
Location loc2 = new Location("Location2");
loc2.setLatitude(geoPoint.getLatitudeE6);
loc2.setLongitude(geoPoint.getLongitudeE6);
and then i would use the distanceTo() to get the distance between the two points.
My Questions
What is the Providername for? ...new Location("What is this here???")
So do i have to define a Provider before or something?
I want to use this code in a for() to calaculate between more GeoPoints.
And btw - i have to convert the E6 Values back to normal?
Not exactly
loc.setLatitude() takes a double latitude. So the correct code is:
loc.setLatitude( geoPoint.getLatitudeE6() / 1E6);
Location() constructor take the name of the GPS provider used. It can be LocationManager.GPS_PROVIDER or NETWORK_PROVIDER among other values
To get the distance between two point you can use the Location class and more precisely the distanceBetween static method.
The doc is quite clear on what it does but here a quick code sample:
float[] results = new float[3];
Location.distanceBetween(destLatitude, destLongitude, mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude(), results);
// result in meters, convert it in km
String distance = String.valueOf(Math.round(results[0] / 1000)) + " km");
To convert from minute/second to degree you can use the convert method of the Location class.
Log.i("MapView", "Map distance to mark (in meters): " + myLocation.distanceTo(GeoToLocation(point)) + "m");
then
public Location GeoToLocation(GeoPoint gp) {
Location location = new Location("dummyProvider");
location.setLatitude(gp.getLatitudeE6()/1E6);
location.setLongitude(gp.getLongitudeE6()/1E6);
return location;
}