I am developing a location based app which have the functionality to update user current location in every 1 minutes.
I am using bellow to code for requesting location updates:
private LocationRequest mLocationRequest;
private static LocationClient mLocationClient;
mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(60000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setFastestInterval(60000);
mLocationClient = new LocationClient(this, this, this);
if (servicesConnected()) {
mLocationClient.connect();
}
servicesConnected() is user defined method which returns true if Google play services is available otherwise returns false
and my overriden method like this:
#Override
public void onConnected(Bundle connectionHint) {
try {
mLocationClient.requestLocationUpdates(mLocationRequest, this);
} catch (IllegalStateException e) {
// TODO: handle exception
}
}
#Override
public void onLocationChanged(Location location) {
// logic to store location data
}
But I found location updates like bellow figure while my GPS is ON :
Please suggest what should I do to overcome unwanted location updates.
Here's some info from OwnTracks https://github.com/owntracks/android/issues/66
From my research the only thing you can do is filter out "bad" locations like this:
#Override
public void onLocationChanged(Location location) {
if(location.getAccuracy() < 210.0) {
// use provided location
}
}
It doesn't appear that there is any way to prevent these updates from being requested using the Fused provider (other than stopping updates or increasing the interval when you have a location you are satisfied with). There's only so much "filtering" that can be done by the GPS itself and those options are the constants inside LocationRequest that you already know about. I believe your issue is hardware related or has to do with the location you are getting updates from (I'm basing this assumption on the OwnTracks data). Google could theoretically offer more advanced Criteria like it used to do with LocationManager, but I believe that would basically do the same thing as my example, except under the hood (i.e. the GPS would still do the work of getting the location and then discard it AFTER it knows the accuracy isn't high enough).
If you want to make it do less work, your best options are increasing the interval or simply stopping updates when you no longer need new locations. For example, if you have a decent location, maybe you raise the interval and keep that location longer. But that depends on what your app is trying to do with the data.
Related
I have read the Android Docs, FusedLocationProvider vs LocationManager; perused the dizzying array of questions and answers around this topic here in stackoverflow; and developed many tests with poor results so far. Why is this so darned confusing and hard to grasp?
I have an app that needs to get a hi-res Location object (lat/long/alt/accuracy/etc) when the user performs an action in the app; let's say they press a button. What is the best way to do this?
I have used the fusedLocationProviderClient.getLastLocation().addOnSuccessListener() and get wildly mixed results.
I have used locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER). If I start the GPS Status app on my Galaxy S9 then this produces quite wonderful results. But if that is not running, then the results are worthless.
What am I missing here? Everyone likes to point to this Doc site or that Example site that is mostly worthless and doesn't really answer this specific question. I have wasted hours pouring over those sites that simply don't answer this question. Please, just sum up the general algorithm that should be used here and the calls to make. That is all I need.
I want to be able to walk around in my yard (10 meters here and there) and press the button and have the app show the lat/long/accuracy/altitude/distance-from-last-location and have it be correct every time within a certain level of accuracy. What do I have to do? I need hi-res accuracy, but the ability to notify the user of accuracy less than say 100ft, and still obtain the best accuracy possible even if it has an error of 400ft.
You are missing how GPS receivers work.
When there is no app using precise location, all smartphones turn off the GPS receiver to conserve battery power.
Even if you selected location services to be on (in settings), you will notice in the notification bar the icon for GPS use is only present when an app is active, like Google Maps or GPS test app.
Once the receiver is turned on (because some app needs it), it takes some time before a "fix" - accurate location measurement is available.
How long it will take to get a fix depends on several things, including environmental conditions, your phone type, time and distance since last accurate fix, etc.
It may take anywhere from several seconds to sever minutes.
So, what you should do, is subscribe to location as soon as your app is opened, and request to receive it as frequently as possible.
Then, enable the button only once you have good accuracy, and when the button is pressed, show the latest result.
You should probably also display some spinner or message to the user while waiting for accurate fix so the user knows your app is not stuck.
Edit: by "subscribe" I mean register the necessary callback so your app will receive the location from the system when it is ready.
How to do this, depends on which API you choose.
There is no error in the google docs.
If you choose to use fused location, you will need to do the following:
Create a location request object and set priority to PRIORITY_HIGH_ACCURACY, also setInterval and setFastestInterval to 1000 (1 second) to get the best accuracy.
Get a FusedLocationProviderClient object from LocationServices
Use the client to register a callback to your app
There are code examples here:
https://developer.android.com/training/location/request-updates
In the callback function in your app you can check the accuracy, and if it is good enough for you enable the button and save the location so you can display it to the user when they click the button.
Ok - this seems to work. This general flow seems to be the answer.
Assumptions: you are requesting android.permission.ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION in manifest.
Just sample code in the onCreate() function of MainActivity for testing purposes.
check to see if we have ACCESS_FINE_LOCATION permission; if not, request.
get FusedLocationProviderClient
get a start location from getLastLocation(); for purposes of comparison and start of track
define locationCallback() to be called by fusedLocationProvider; all we are interested in is getting the last one in the stack and save to class Field.
define LocationRequest with interval of 5 secs and PRIORITY_HIGH_ACCURACY
check to see if the user device is allowing this; not sure what to do with this other than to notify user if not allowed.
now requestLocationUpdates using the LocationCallback defined above.
when user performs action needing current lat/long (e.g. press button), retrieve class field populated with Location object on last LocationCallback().
I am very open to feedback on this pattern. Hope it helps others (as there is a plethora of questions about this). And would love to hear about any problems with this design or issues that I may encounter.
if (Build.VERSION.SDK_INT >= 23) {
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE_ASK_PERMISSIONS);
} else {
// getFusedLocationProviderClient
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
// getStartLocation
fusedLocationProviderClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if (location != null) {
StartLocation.set(location);
}
}
}).addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
}
});
// Define LocationCallback
locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult != null) {
LastLocation = locationResult.getLastLocation();
}
}
};
// Now lets request location updates - that is how this must happen
// https://developer.android.com/training/location/change-location-settings
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setInterval(5000);
locationRequest.setFastestInterval(1000);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Attempt to see if requested settings are compatible with user device.
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(locationRequest);
// Check to see if location settings are satisfied by user's device settings?
SettingsClient client = LocationServices.getSettingsClient(this);
Task<LocationSettingsResponse> locationTask = client.checkLocationSettings(builder.build())
.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
}
}).addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
if (e instanceof ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
}
Toast.makeText(MainActivity.this, "Location Settings Are Not " +
"Correct On This Device", Toast.LENGTH_LONG).show();
}
});
// Request location updates
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper());
}
}
I am using Fused Location Api for location updates in my app. When I request for location updates, GPS is getting ON(we can see location symbol in status bar) and when I am removing location updates by calling removeLocationUpdates,sometimes GPS is not switching off(we can see still location symbol in status bar).No other app is using GPS at this point of time other than my app.
This is resulting in consuming more battery by the app.
Creating required object instances
mLocationClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(connectCallbackListener)
.addOnConnectionFailedListener(connectFailedListnr)
.addApi(LocationServices.API).build();
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL_IN_MILLISECONDS);
Requesting for location updates
LocationServices.FusedLocationApi.requestLocationUpdates(mLocationClient, mLocationRequest, mLocationListener);
Removing location updates
if (mLocationClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mLocationClient, mLocationListener);
}
mLocationClient.disconnect();
Anyone has any idea about this issue ?
I had the same issue. Not FusedLocationApi is keeping the GPS running, even if the App is put to background and onStop() was fired. It's GoogleMap!! I had included a Map in another Fragment and didn't recognized for a while. I think also Renadh has a GoogleMap View included.
So, to only keep GPS running in your App while it is running put
#Override
public void onStop() {
mGoogleMap.setMyLocationEnabled(false);
super.onStop();
}
to your Fragment/Activity.
Don't forget to enable your location with
mGoogleMap.setMyLocationEnabled(true);
if you require the blue marker in your mapview. Either in onCreate() or wherever you set up your map.
I'm trying to get location manager to work in an Activity in my Android app but it keeps giving me the error "cannot resolve method requestLocationUpdates"
I'm putting this code in my OnCreate (found from other examples):
// Acquire a reference to the system Location Manager
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
// Called when a new location is found by the network location provider.
makeUseOfNewLocation(location);
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
// Register the listener with the Location Manager to receive location updates
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
I want to use my own "OnLocationChanged" method to update a map with the users location, but I can't figure out why I'm getting this error.
Any ideas why I'm getting the error?
Is there a better more modern way to implement location updates?
Thanks!
I would recommend you look into the new FusedLocationProviderApi that is part of Google Play Services. From the docs:
The Google Location Services API, part of Google Play Services,
provides a more powerful, high-level framework that automatically
handles location providers, user movement, and location accuracy. It
also handles location update scheduling based on power consumption
parameters you provide. In most cases, you'll get better battery
performance, as well as more appropriate accuracy, by using the
Location Services API.
Make sure you're important the correct LocationClient, should be com.google.android.gms.location.LocationClient and you might be importing android.location.LocationClient
I simply need to get the user location. Preferably the exactly location, but if it's not possible, a rough location would be fine.
According to the docs:
LocationClient.getLastLocation()
Returns the best most recent location currently available.
and
LocationManager.getLastKnownLocation(String)
Returns a Location indicating the data from the last known location fix obtained from the given provider.
If my understanding is right, the former will give me a very good result (or null sometimes) while the latter will give me a result which would rarely be null.
This is my code (simplified)
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationClient = new LocationClient(this, this, this);
#Override
public void onConnected(Bundle dataBundle) {
setUserLocation();
}
private void setUserLocation() {
myLocation = locationClient.getLastLocation();
if (myLocation == null) {
myLocation = locationManager.getLastKnownLocation(locationManager.getBestProvider(new Criteria(), false));
if (myLocation == null) {
//I give up, just set the map somewhere and warn the user.
myLocation = new Location("");
myLocation.setLatitude(-22.624152);
myLocation.setLongitude(-44.385624);
Toast.makeText(this, R.string.location_not_found, Toast.LENGTH_LONG).show();
}
} else {
isMyLocationOK = true;
}
}
It seems to be working but my questions are:
Is my understanding of getLastLocation and getLastKnownLocation correct?
Is this a good approach?
Can I get in trouble using both in the same activity?
Thanks
LocationClient.getLastLocation() only returns null if a location fix is impossible to determine. getLastLocation() is no worse than getLastKnownLocation(), and is usually much better. I don't think it's worth "falling back" to getLastKnownLocation() as you do.
You can't get into trouble using both, but it's overkill.
Of course, you have to remember that LocationClient is part of Google Play Services, so it's only available on devices whose platform includes Google Play Store. Some devices may be using a non-standard version of Android, and you won't have access to LocationClient.
The documentation for Google Play Services discusses this in more detail.
I'm having little problem with getting my current location using NETWORK_PROVIDDER.
My code looks like this:
LocationManager lMgr = (LocationManager) context
.getSystemService(Context.LOCATION_SERVICE);
boolean isNetworkProviderEnabled = lMgr
.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
Location location = lMgr.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (location != null) {
// deal somehow with last (very likely outdated location)
}
if (isNetworkProviderEnabled) {
lMgr.requestLocationUpdates(provider, 0, 0, locationListener);
}
Of course I have MyLocationListener that deals with location changes and ALL REQUIRED PERMISSIONS ARE ADDED TO MANIFEST
And the problem is that on some phones this code works like charm, but one others, the "requestLocationUpdates" does totally nothing. Of course on those problematic phones, when I open Google Maps application, my current location appears immediately. So my question is (I believe that people from Google should answer this): how this is done that Google Maps retrieves current location immediately, and other apps don't? Is my code wrong? Of course I have seen code like this in many stackoverflow questions. If anyone wish to know, this kind of problem appears on some Samsung Galaxy Nexus S phones
In my application GPS is not used to save battery power, but location services are enabled.
I have recently faced the same issue, LocationManager is buggy and not implemented completely on Samsung phones. They also consume a lot of power. Use LocationClient to solve both these issues. LocationClient uses all means available to get you the last location, so its the super set of all your providers and sensors.
I faced issues with the Samsung Y model phones, I wonder which phones you are talking about. To fix the problem with Samsung phones, I kickstarted the GPS on the phone with
HomeScreen.getLocationManager().requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 0, 0, new LocationListener() {
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onLocationChanged(final Location location) {
}
});
And then called the LocationManager.getLastKnownLocation OR the new locationClient.getLastLocation api.
First, just add the above lines over your getLastKnownLocation. Things should magically start workings
Migrate to LocationClient when you have more time and test again. Use the magic above to get it working if it fails.
Sometimes device does not receive any location updates and GPS_PROVIDER and NETWORK_PROVIDER returns null.
Try restarting your device, this trick helped me. My code was perfectly fine but providers were returning null.