Display distance between 2 locations on a ListView - android

I have this View Adapter method for a ListView which is populated from a JSON file.
One of the components I wanna display on a TextView of each list item is the distance between the user's location and each location which is displayed on the ListView.
But the app crashed everytime I run it, I know there's something wrong with my code starting from //calculate the distance.
Can anybody help me to analyze and fix on the lines where I went wrong probably?
Here's the sample of the parsed longitude and latitude from the JSON:
"latitude": 52.5074779785632,
"longitude": 13.3903813322449,
and here's the method I'm using:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null){
convertView = LocationsListActivity.this.getLayoutInflater().inflate(R.layout.listitems, null, true);
}
VideoLocation vidLocation = videoLocations[position];
ImageView v = (ImageView)convertView.findViewById(R.id.image);
String url = vidLocation.documentary_thumbnail_url;
v.setTag(url);
loader.DisplayImage(url, ctx, v);
TextView titleView = (TextView)convertView.findViewById(R.id.txt_title);
String title = vidLocation.name;
titleView.setText(title.toUpperCase());
TextView descView = (TextView)convertView.findViewById(R.id.txt_list_desc);
String desc = vidLocation.text;
descView.setText(desc);
//calculate the distance
Location newLocation = new Location("User");
GeoPoint geopoint = new GeoPoint(
(int) (newLocation.getLatitude() * 1E6), (int) (newLocation
.getLongitude() * 1E6));
GeoPoint myposition = geopoint;
Location locationA = new Location("point A");
Location locationB = new Location("point B");
locationA.setLatitude(geopoint.getLatitudeE6() / 1E6);
locationA.setLongitude(geopoint.getLongitudeE6() / 1E6);
locationB.setLatitude(vidLocation.latitude/ 1E6);
locationB.setLongitude(vidLocation.longitude / 1E6);
double distance = locationA.distanceTo(locationB);
String distances = String.valueOf(distance);
TextView distanceView = (TextView)convertView.findViewById(R.id.txt_distance);
System.out.println(distances);
distanceView.setText(distances+" m");
return convertView;
}

When your application crashes and you ask about it on StackOverflow, you should always include the logcat output of the crash details. The answer is almost always right there and very easy to pick out.
What you're doing here is using the Location object incorrectly. If you look at the docs for the constructor you're using, you'll see that this just returns a default location object and doesn't contain the devices actual location. Also, the string that you pass into this is not arbitrary, it's the name of the location provider to be associated with this Location object.
To get the user's last known location, get an instance of the LocationManager and call getLastKnownLocation. This also takes a string which corresponds to a location provider that should be used.
Read the docs on obtaining user location and look into the Criteria object and the LocationManager.getBestProvider method. These are the safest ways to get the best location and not crash in the process. For example, if you request location passing the GPS provider string and the device doesn't have a GPS or the user has their GPS turned off, your code will crash (I believe you get a null object from getLastKnownLocation in this case). Also make sure to add the appropriate permissions to the manifest.
http://developer.android.com/guide/topics/location/obtaining-user-location.html
http://developer.android.com/reference/android/location/Criteria.html
http://developer.android.com/reference/android/location/LocationManager.html

Location newLocation = new Location("User");
"User" is not a valid LocationProvider. It should at least be one of
LocationManager.getAllProviders();
(Usually "gps" or "network")
Also, in your code, newLocation is not really initialized. Its values are most likely empty. You should obtain the user location with something like, for instance:
LocationManager.getLastKnownLocation(null);

Related

Android: Issue in calculating distance using Location manager

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

compare my GPS location to a list - android

In my android app I'm trying to compare user location with a list of stores coordinates.
I already know how to get user coordinates and I already have the list as a array.
How can I compare both and find the nearest store?
float shortestDistance = Float.MAX_VALUE;
Location closestLocation = null;
for(Location loc : locations){
if(yourLocation.distanceTo(loc) < shortestDistance){
shortestDistance = yourLocation.distanceTo(loc);
closestLocation = loc;
}
}

Getting Location from coordinates

I have given coordinates for latitude and longitude, and I want make a location object with those.There isn't a constructor that takes to doubles to make a location, so I tried like this:
Location l = null;
l.setLatitude(lat);
l.setLongitude(lon);
but it crashes. Any different idea?
Just create a new Location with new Location("reverseGeocoded");
like this
GeoPoint newCurrent = new GeoPoint(59529200, 18071400);
Location current = new Location("reverseGeocoded");
current.setLatitude(newCurrent.getLatitudeE6() / 1e6);
current.setLongitude(newCurrent.getLongitudeE6() / 1e6);
current.setAccuracy(3333);
current.setBearing(333);
This crashes because you cannot call methods on an non existent object.
I presume you are talking about android.location.Location?
This is usually returned by the various positioning services of Android.
What do you want to do with it?
Do you want to reverse geocode it? As in find an address for that geo coordinate?
Or do you want to use it as a "fake" position and feed it to other applications?
There are BTW two constructors. One takes the name of a positioning service and the other is a copy constructor and takes an existing Location.
So you could create a Location like this:
Location l = new Location("network");
But I do not think that this will result in something you want to have.
Here is a link to the documentation:
https://developer.android.com/reference/android/location/Location.html#Location%28java.lang.String%29
Location l = new Location("any string");
l.setLatitude(lat);
l.setLongitude(lon);
Try this:
public double lat;
public double lon;
public void onLocationChanged(Location loc)
{
lat=loc.getLatitude();
lon=loc.getLongitude();
Toast.makeText(getBaseContext(),"Latitude:" + lat +Longitude"+lon,Toast.LENGTH_LONG).show();
}

Refresh Latitude/Longitude or load faster

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

Geo Point vs Location

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;
}

Categories

Resources