I know that I can get distance with google api and it is very good
But is it slow sometimes and not possible for my app
Is there any way to get distance between two location?
You should use Location.distanceBetween() or Location.distanceTo()
You could easily get the lastKnownLocation, add the co-ordinates to an ArrayList and then measure the distance between the points in that list as shown below:
Prerequisites:
Add permissions to manifest:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Import Gradle Dependencies:
compile 'com.google.android.gms:play-services-location:10.2.1'
Add this class to your project:
Github: android-maps-utils : SphericalUtil.java
Implement LocationListener in your Activity:
public class myClass extends Activity implements LocationListener {
Define your global Variables:
private LocationManager locationManager;
private String provider;
private ArrayList<LatLng> coordList = new ArrayList<String>();
Get Initial Location (in onCreate() or onClick()):
locationManager = (LocationManager) getActivity().getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
// Define the criteria how to select the locatioin provider -> use
// default
Criteria criteria = new Criteria();
provider = locationManager.getBestProvider(criteria, false);
Location location = locationManager.getLastKnownLocation(provider);
if (coordList != null && !coordList.isEmpty()) {
coordList.get(0);
} else {
coordList.add(0, new LatLng(location.getLatitude(), location.getLongitude()));
}
if (location != null) {
onLocationChanged(location);
}
getLocationUpdates();
create a getLocationUpdates() method:
private void getLocationUpdates() {
if (locationManager != null) {
checkPermission();
locationManager.requestLocationUpdates(provider, ONE_SECOND, ONE_METER, this);
}
}
Request location updates from your locationManager (make sure you requestPermission for Android 6.0 and up)
#Override
public void onResume() {
super.onResume();
getLocationUpdates();
}
Use the SphericalUtil class to compute the distance within the ArrayList inside the onLocationChange function.
#Override
public void onLocationChanged(Location location) {
double distance = SphericalUtil.computeLength(coordList);
distance = round(distance, 2) / 1000;
distanceOutput.setText(distance + "km");
}
Add the round functionality:
public static double round(double value, int places) {
if (places < 0) throw new IllegalArgumentException();
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(places, RoundingMode.FLOOR);
return bd.doubleValue();
}
This will get the distance between start and end points in km and round it down to two decimal places, feel free to convert them into any other unit of distance depending on your use-case.
Google Distance matrix API need to use for the correct distance between places.
After many search and faq,Finally I understood that google's api is best and first way to get distance two location
Related
I am creating an app with a google maps and a circle radius centered on the user’s location. I want the user to choose the desired radius of the circle with a spinner (1-10 km radius). But when I use the value from my spinner the radius circle doesn't appear.
For the location I can get the blue dot showing my appearance by: map.setMyLocationEnabled(true); and I can manually enter a location for map to zoom into. But when I try to zoom into and set center of circle on the device location I get a nullpointerexception error. Below is my code for the location and the toast is just for me to see that I get the actual location.
private void getDeviceLocation() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]
{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
return;
}
Task<Location> task = mFusedLocationClient.getLastLocation();
task.addOnSuccessListener(MainActivity.this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if (location != null) {
currentLocation = location;
Toast.makeText(MainActivity.this, "Current Position " + currentLocation.getLongitude(), Toast.LENGTH_LONG).show(); //Just to make sure we have a value
SupportMapFragment supportMapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map2);
supportMapFragment.getMapAsync(MainActivity.this);
}
}
});
}
Then I use userPosition for map to zoom into and set center of circle
public void onMapReady(GoogleMap map) {
LatLng userPosition = new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude());
mGoogleMap = map;
map.setMyLocationEnabled(true);
map.animateCamera(CameraUpdateFactory.newLatLngZoom(userPosition, 10f));
map.addCircle(new CircleOptions()
.center(userPosition)
.radius(mapRadius)
.strokeColor(0x330073FF)
.fillColor(0x330073FF)
.strokeWidth(2));
map.getUiSettings().setZoomControlsEnabled(true);
map.getUiSettings().setMyLocationButtonEnabled(true);
}
But here I get the error on the line userPosition: java.lang.NullPointerException: Attempt to invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference
at com.example.test.MainActivity.onMapReady(MainActivity.java:362).
I got the code from a tutorial and it seems to work for them and tried many different tutorials as well with slightly different code so not sure what I do wrong. I have tried searching and know others had similar problems but still haven't gotten it to work.
As for the radius, it works fine when I set a manual location and write It works well if I write the radius myself in meters. But if I try to use my spinner and the mapRadius value, the radius circle doesn’t show up at all when I run the emulator. This is the code that is in onCreate
spinnerRadius = findViewById(R.id.spinner_radius);
ArrayAdapter<CharSequence> spinnerAdapter = ArrayAdapter.createFromResource(this,
R.array.spinner_radius_option, android.R.layout.simple_spinner_item);
spinnerRadius.setAdapter(spinnerAdapter);
spinnerRadius.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
mapRadiusInput = parent.getItemAtPosition(position).toString();
mapRadius = Double.parseDouble(mapRadiusInput)*1000; //converting to meters
Toast.makeText(MainActivity.this, ""+mapRadius, Toast.LENGTH_LONG).show();
}
I am a beginner when it comes to programming and android and I spent quite a bit on time on these two problem and it wouldn’t surprise me if it is easy to solve. Any help or pointers would be greatly appreciated.
When you add the circle, save the return value (Circle) in a field variable, Circle myCircle.
Then in the onItemSelected update the circle radius with the value (in meters).
So, first declare the variable as a class field variable (for scope visibility later). I'm assuming this is all in one class - if not you'll need to make this variable accessible to the onItemSelected callback instance.
private Circle myCircle;
Then when adding the circle, save it:
myCircle = map.addCircle(new CircleOptions()
.center(userPosition)
.radius(mapRadius)
.strokeColor(0x330073FF)
.fillColor(0x330073FF)
.strokeWidth(2));
And in your onItemSelected, update the circle (in meters)
myCircle.setRadius(mapRadius);
Here's another example showing same thing: https://stackoverflow.com/a/38454501/2711811
And API doc: https://developers.google.com/android/reference/com/google/android/gms/maps/model/Circle.html#setRadius(double)
The key is to save the Circle when it's created. And as you can see from the API, with the Circle reference there are other setters which can be used.
I am new to android development but am taking a shot at making myself a golf rangefinder.. I have this activity -
public class hole_1 extends Activity implements View.OnClickListener {
Button nextBtn;
GPSTracker gps;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hole_1);
gps = new GPSTracker(hole_1.this);
// Get Variable From Home Activity
Bundle extras = getIntent().getExtras();
String course = null;
if (extras != null) {
course = extras.getString("Course");
}
//Set Next Hole Button
nextBtn = (Button) findViewById(R.id.nextButton);
nextBtn.setOnClickListener(this);
gps = new GPSTracker(hole_1.this);
if (gps.canGetLocation()) {
double latitude = gps.getLatitude();
double longitude = gps.getLongitude();
double lat2 = 39.765718;
double lon2 = -121.860080;
Location loc1 = new Location("");
loc1.setLatitude(latitude);
loc1.setLongitude(longitude);
Location loc2 = new Location("");
loc2.setLatitude(lat2);
loc2.setLongitude(lon2);
float distanceInMeters = loc1.distanceTo(loc2);
int myDist = (int) (distanceInMeters * 1.0936);
TextView latView = (TextView) findViewById(R.id.yardage);
latView.setText(String.valueOf(myDist));
}else{
gps.showSettingsAlert();
}
}
#Override
public void onClick(View v) {
Intent myIntent = new Intent(this, end.class);
myIntent.putExtra("Hole",1);
startActivity(myIntent);
}
}
What I would like to do is update the myDist variable which is the distance between my current coordinates and the fixed coordinates (lat2, lon2). I have done some research and found asyncTask, threading and setting a timer but cannot figure out the best method for this application.. The app works great as is but I have to refresh the page to get updated distances and would like it to just update itself every few seconds.. What should I do?
Thanks!
1)You can't update every couple of seconds. GPS only updates every 30s to a minute.
2)You wouldn't use an async task here or any oter form of threading, GPS works on a callback system. You request updates and it will call you back whenever an update is available.
3)DO NOT USE the GpsTracker LIBRARY EVER. It's broken. Badly. See the full writeup I have on why its broken at http://gabesechansoftware.com/location-tracking/
I am having trouble figuring how to get the distance between 2 non fixed locations. The first location is my current location and the second is the latest current location after walking say 100 meters. Below is a snippet of code.
/**
* Callback that fires when the location changes.
*/
#Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
updateUI();
}
/**
* Updates the latitude, the longitude, and the last location time in the UI.
*/
private void updateUI() {
latitude = mCurrentLocation.getLatitude();
longitude = mCurrentLocation.getLongitude();
mLatitudeTextView.setText(String.format("%s: %f", mLatitudeLabel,latitude));
mLongitudeTextView.setText(String.format("%s: %f", mLongitudeLabel, longitude));
}
So below I have my mCurrentLocation but how do I get the newCurrentLocation so I use the distanceTo method.
double distance = mCurrentLocation.distanceTo(newCurrentLocation);
Any suggestions would be much appreciated.
You'll have to save the current location in a temporary variable, something like this:
public void onLocationChanged(Location location) {
Location temp = mCurrentLocation; //save the old location
mCurrentLocation = location; //get the new location
distance = mCurrentLocation.distanceTo(temp); //find the distance
updateUI();
}
I've done the prep work of finding accurate latitude/longitude (in decimal number notation) coordinates for all 6 Hooters restaurant locations in Wisconsin. I intend to store those coordinate values in an array of a separate class. I also already have a Location Listener in my code to get the user's current GPS location. See my code below:
package sam.finalmap.hooters;
// Camera is the view of the map.
import com.google.android.gms.maps.CameraUpdateFactory;
// the google map
import com.google.android.gms.maps.GoogleMap;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color; // for drawing a line.
import android.location.Location; // for detecting location changes with the GPS.
import android.location.LocationListener; // to listen for location changes
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.maps.MapFragment; // the Map class.
import com.google.android.gms.maps.model.LatLng; // for creating lattitudes and longitutes in memory.
import com.google.android.gms.maps.model.Polyline; // used to draw from one location to the other
import com.google.android.gms.maps.model.PolylineOptions;
/**
* Draws a map, uses GPS to get the current location, the draws a line from Eau CLaire (see constants)
* to the new position, which will be the closest Hooters restaurant to the user's current location.
* This is the AdapterView.
*
* #author daviddalsveen
*
*/
public class GMapsLocationPath extends Activity implements LocationListener {
/** Called when the activity is first created. */
private GoogleMap mMap;
// constants to hard code all 6 of Wisconsin's Hooters restaurant points on the map:
private static final float Appleton_LAT = 44.2655012f;
private static final float Appleton_LNG = -88.4768057f;
private static final float Brookfield_LAT = 43.03645f;
private static final float Brookfield_LNG = -88.124937f;
private static final float EastMadison_LAT = 43.132432f;
private static final float EastMadison_LNG = -89.3016256f;
private static final float GreenBay_LAT = 44.477903f;
private static final float GreenBay_LNG = -88.067014f;
private static final float Janesville_LAT = 42.7215666f;
private static final float Janesville_LNG = -88.9889661f;
private static final float LaCrosse_LAT = 43.8109318f;
private static final float LaCrosse_LNG = -91.2536215f;
private LocationManager locationManager;
private TextView tv; // a Textview for displaying lattitude and longitude.
private float curLat = 44.88f; // current position -- assigned constants for
// testing...
private float curLng = -91.47f;
#Override
public void onCreate(Bundle savedInstanceState) {
// called when the activity is first started.
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// recommended method by google to make the map object.
setUpMapIfNeeded();
// Sets the map type to be "normal"
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
tv = (TextView) findViewById(R.id.label1);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
500, 1, this);
Location location = locationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
// 500 is the minimum time interval to update, in milliseconds
// 1 is the distance in meters in which to sense an update.
// 'this' is the pending intent.
// center latitude and longitude for EC
float lat = Appleton_LAT;
float lng = Appleton_LNG;
// debug example...
Toast.makeText(this, "" + (int) (lat * 1E6), Toast.LENGTH_LONG).show();
if (location == null) { // no last known location
locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER,
this, null);
// Create a new Lattitude Longitude Object, passing it the
// coordinates.
LatLng latLng = new LatLng(lat, lng);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 10.0f));
// re-draw
} else {
// explicitly call and update view with last known location or the
// one set above.
onLocationChanged(location);
}
}
/**
* Checks to see that the map exists, if not, creates one.
*/
private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the
// map.
if (mMap == null) {
mMap = ((MapFragment) getFragmentManager().findFragmentById(
R.id.map)).getMap();
// Check if we were successful in obtaining the map.
if (mMap != null) {
// The Map is verified. It is now safe to manipulate the map.
}// else?
}
}
// Java Interface RULE NOTE: that we must implement every method of
// interface LocationListener,
// whether we use the method or not.
/**
* Use the GPS to get the current location of the user
*
*/
public void onLocationChanged(final Location loc) {
String lat = String.valueOf(loc.getLatitude());
String lon = String.valueOf(loc.getLongitude());
Log.e("GPS", "location changed: lat=" + lat + ", lon=" + lon);
tv.setText("lat=" + lat + ", lon=" + lon);
curLat = Float.parseFloat(lat); // update the current lattitude and longitude.
curLng = Float.parseFloat(lon);
// Create a new Lattitude Longitude Object, passing it the coordinates.
LatLng latLng = new LatLng(curLat, curLng);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 10.0f));
// re-draw
draw();
}
public void onProviderDisabled(String loc) {
Log.e("GPS", "provider disabled " + loc);
}
public void onProviderEnabled(String loc) {
Log.e("GPS", "provider enabled " + loc);
}
/**
* loc: name of location provider status: status of location provider
* (temporarily unavailable, etc) extras: optional bundle with additional
* status information
*/
public void onStatusChanged(String loc, int status, Bundle extras) {
Log.e("GPS", "status changed to " + loc + " [" + status + "]");
}
/**
* Draw a line from
*/
public void draw() {
float lat = 44.88f;
float lng = -91.48f;
// Instantiates a new Polyline object and adds points to define a
// endpoints of a line
PolylineOptions rectOptions = new PolylineOptions().add(
new LatLng(curLat, curLng))
.add(new LatLng(lat, lng)); // Closes the polyline.
// Set the rectangle's color to red
rectOptions.color(Color.RED);
// Get back the mutable Polyline
Polyline polyline = mMap.addPolyline(rectOptions);
}
}
What I want help with here is finding a way to parse through the array, and compare the difference of the user's location with each of the 6 restaurant locations, and whichever difference is smallest (whichever restaurant location is closest to the user) is the restaurant that will be selected and who's information will displayed.
That said, how do I tell it to use the smallest difference after it finishes parsing through the array and getting all 6 of the latitude/longitude differences?
/**
* My teacher suggested subtracting the current latitudes and longitudes from the restaurant latitudes and
* longitudes to see if they fall within a certain range (lets just say less than 10). Then, using the resulting
* differences as absolute values in an if statement (if absolute value < 10 for both are true), that restaurant
* would be the one selected:
*/
//float[] H_Latitude = {44.2655012f, 43.03645f, 43.132432f, 44.477903f, 42.7215666f, 43.8109318f};
//float[] H_Longitude = {-88.4768057f, -88.124937f, -89.3016256f, -88.067014f, -88.9889661f, -91.2536215f};
float LATdifference = curLat - H_Latitude;
float LNGdifference = curLng - H_Longitude;//I'm pretty sure I can't use "H_Longitude and H_Latitude", because
//they're merely the name of the array. So how do I access the elements inside of them? How do I successfully
//address them with a reference variable that I can use to dynamically subtract from curLat and curLng and get
//what I need to replace the "i" in the for loops:
for (float LATdifference = 0; i < 4; i++) {
System.out.println (count[i]);
}
Try Location.distanceBetween(): reference
You could feed the GPS coordinates into the Google Directions API and use the travel distance to determine the closest store.
The Android Location class has a distanceTo or distanceBetween method that you could use to get a straight line distance between 2 GPS points. You could use this to narrow it down to 2-3 candidates and then use the directions api to get a final answer.
I have made an Android app that gets location by longitude and latitude on a button click.
At first I get the last known location reading, which is, for argument sake, inaccurate when I first load up the app/turn on gps.
What I would like to know is how to wait for it to be accurate, like in Google maps when you get the toast message 'waiting for location'.
If you see any way the code can be improved it would also be helpful.
Code for reference:
public class Clue extends Activity {
public static double latitude;
public static double longitude;
Criteria criteria;
LocationManager lm;
LocationListener ll;
Location location;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.questions);
criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
ll = new MyLocationListener();
lm.requestLocationUpdates(lm.getBestProvider(criteria, true), 0, 0, ll);
}
private boolean weAreThere() {
location = getLocation();
longitude = location.getLongitude();
latitude = location.getLatitude();
return inCorrectPlace(param);
}
private Location getLocation() {
lm.requestLocationUpdates(lm.getBestProvider(criteria, true), 0, 0, ll);
return lm.getLastKnownLocation(lm.getBestProvider(criteria, true));
}
}
public class MyLocationListener implements LocationListener
{
public void onLocationChanged(Location loc)
{
Clue.longitude = loc.getLongitude();
Clue.latitude = loc.getLatitude();
}
}
Thanks for reading, all replies will be appreciated.
Ben
If Location.hasAccuracy() returns true, you could call Location.getAccuracy() to retrieve the accuracy in meters, then filter the ones you don't consider enough accurate.
Notice you are not using LocationManager.GPS_PROVIDER so your fixes could also be obtained by other means (like WiFi).
Usually expect about a minute for the GPS chip to get "hot"* before getting GPS fixes (outdoors).
*By hot I mean having satellites coverage. Some chipsets get disconnected ("cold") after some time to preserve battery. The Time To First Fix (TTFF) is greater when the chip is cold.
Here is an excellent explanation,
http://android-developers.blogspot.com/2011/06/deep-dive-into-location.html
helps you understand exactly how to implement it.
Initially , u should get fix using getlastknownLocation ()
In addition, U can use a background service that updates location using NETWORK.PROVIDER... which shall not drain ur battery if used judiciously...and also works if GPS is turned off
If there is no network provider, then u should try and ask user to turn on GPS.
If u r using 2.2 try PASSIVE PROVIDER