Good way of getting the user's location in Android
Solution 1
Looks like we're coding the same application ;-)
Here is my current implementation. I'm still in the beta testing phase of my GPS uploader app, so there might be many possible improvements. but it seems to work pretty well so far.
/**
* try to get the 'best' location selected from all providers
*/
private Location getBestLocation() {
Location gpslocation = getLocationByProvider(LocationManager.GPS_PROVIDER);
Location networkLocation =
getLocationByProvider(LocationManager.NETWORK_PROVIDER);
// if we have only one location available, the choice is easy
if (gpslocation == null) {
Log.d(TAG, "No GPS Location available.");
return networkLocation;
}
if (networkLocation == null) {
Log.d(TAG, "No Network Location available");
return gpslocation;
}
// a locationupdate is considered 'old' if its older than the configured
// update interval. this means, we didn't get a
// update from this provider since the last check
long old = System.currentTimeMillis() - getGPSCheckMilliSecsFromPrefs();
boolean gpsIsOld = (gpslocation.getTime() < old);
boolean networkIsOld = (networkLocation.getTime() < old);
// gps is current and available, gps is better than network
if (!gpsIsOld) {
Log.d(TAG, "Returning current GPS Location");
return gpslocation;
}
// gps is old, we can't trust it. use network location
if (!networkIsOld) {
Log.d(TAG, "GPS is old, Network is current, returning network");
return networkLocation;
}
// both are old return the newer of those two
if (gpslocation.getTime() > networkLocation.getTime()) {
Log.d(TAG, "Both are old, returning gps(newer)");
return gpslocation;
} else {
Log.d(TAG, "Both are old, returning network(newer)");
return networkLocation;
}
}
/**
* get the last known location from a specific provider (network/gps)
*/
private Location getLocationByProvider(String provider) {
Location location = null;
if (!isProviderSupported(provider)) {
return null;
}
LocationManager locationManager = (LocationManager) getApplicationContext()
.getSystemService(Context.LOCATION_SERVICE);
try {
if (locationManager.isProviderEnabled(provider)) {
location = locationManager.getLastKnownLocation(provider);
}
} catch (IllegalArgumentException e) {
Log.d(TAG, "Cannot acces Provider " + provider);
}
return location;
}
Edit: here is the part that requests the periodic updates from the location providers:
public void startRecording() {
gpsTimer.cancel();
gpsTimer = new Timer();
long checkInterval = getGPSCheckMilliSecsFromPrefs();
long minDistance = getMinDistanceFromPrefs();
// receive updates
LocationManager locationManager = (LocationManager) getApplicationContext()
.getSystemService(Context.LOCATION_SERVICE);
for (String s : locationManager.getAllProviders()) {
locationManager.requestLocationUpdates(s, checkInterval,
minDistance, 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(Location location) {
// if this is a gps location, we can use it
if (location.getProvider().equals(
LocationManager.GPS_PROVIDER)) {
doLocationUpdate(location, true);
}
}
});
// //Toast.makeText(this, "GPS Service STARTED",
// Toast.LENGTH_LONG).show();
gps_recorder_running = true;
}
// start the gps receiver thread
gpsTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
Location location = getBestLocation();
doLocationUpdate(location, false);
}
}, 0, checkInterval);
}
public void doLocationUpdate(Location l, boolean force) {
long minDistance = getMinDistanceFromPrefs();
Log.d(TAG, "update received:" + l);
if (l == null) {
Log.d(TAG, "Empty location");
if (force)
Toast.makeText(this, "Current location not available",
Toast.LENGTH_SHORT).show();
return;
}
if (lastLocation != null) {
float distance = l.distanceTo(lastLocation);
Log.d(TAG, "Distance to last: " + distance);
if (l.distanceTo(lastLocation) < minDistance && !force) {
Log.d(TAG, "Position didn't change");
return;
}
if (l.getAccuracy() >= lastLocation.getAccuracy()
&& l.distanceTo(lastLocation) < l.getAccuracy() && !force) {
Log.d(TAG,
"Accuracy got worse and we are still "
+ "within the accuracy range.. Not updating");
return;
}
if (l.getTime() <= lastprovidertimestamp && !force) {
Log.d(TAG, "Timestamp not never than last");
return;
}
}
// upload/store your location here
}
Things to consider:
do not request GPS updates too often, it drains battery power. I currently use 30 min as default for my application.
add a 'minimum distance to last known location' check. without this, your points will "jump around" when GPS is not available and the location is being triangulated from the cell towers. or you can check if the new location is outside of the accuracy value from the last known location.
Solution 2
To select the right location provider for your app, you can use Criteria objects:
Criteria myCriteria = new Criteria();
myCriteria.setAccuracy(Criteria.ACCURACY_HIGH);
myCriteria.setPowerRequirement(Criteria.POWER_LOW);
// let Android select the right location provider for you
String myProvider = locationManager.getBestProvider(myCriteria, true);
// finally require updates at -at least- the desired rate
long minTimeMillis = 600000; // 600,000 milliseconds make 10 minutes
locationManager.requestLocationUpdates(myProvider,minTimeMillis,0,locationListener);
Read the documentation for requestLocationUpdates for more details on how the arguments are taken into account:
The frequency of notification may be controlled using the minTime and minDistance parameters. If minTime is greater than 0, the LocationManager could potentially rest for minTime milliseconds between location updates to conserve power. If minDistance is greater than 0, a location will only be broadcasted if the device moves by minDistance meters. To obtain notifications as frequently as possible, set both parameters to 0.
More thoughts
- You can monitor the accuracy of the Location objects with Location.getAccuracy(), which returns the estimated accuracy of the position in meters.
- the
Criteria.ACCURACY_HIGH
criterion should give you errors below 100m, which is not as good as GPS can be, but matches your needs. - You also need to monitor the status of your location provider, and switch to another provider if it gets unavailable or disabled by the user.
- The passive provider may also be a good match for this kind of application: the idea is to use location updates whenever they are requested by another app and broadcast systemwide.
Solution 3
Answering the first two points:
GPS will always give you a more precise location, if it is enabled and if there are no thick walls around.
If location did not change, then you can call getLastKnownLocation(String) and retrieve the location immediately.
Using an alternative approach:
You can try getting the cell id in use or all the neighboring cells
TelephonyManager mTelephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
GsmCellLocation loc = (GsmCellLocation) mTelephonyManager.getCellLocation();
Log.d ("CID", Integer.toString(loc.getCid()));
Log.d ("LAC", Integer.toString(loc.getLac()));
// or
List<NeighboringCellInfo> list = mTelephonyManager.getNeighboringCellInfo ();
for (NeighboringCellInfo cell : list) {
Log.d ("CID", Integer.toString(cell.getCid()));
Log.d ("LAC", Integer.toString(cell.getLac()));
}
You can refer then to cell location through several open databases (e.g., http://www.location-api.com/ or http://opencellid.org/ )
The strategy would be to read the list of tower IDs when reading the location. Then, in next query (10 minutes in your app), read them again. If at least some towers are the same, then it's safe to use getLastKnownLocation(String)
. If they're not, then wait for onLocationChanged()
. This avoids the need of a third party database for the location. You can also try this approach.
Solution 4
This is my solution which works fairly well:
private Location bestLocation = null;
private Looper looper;
private boolean networkEnabled = false, gpsEnabled = false;
private synchronized void setLooper(Looper looper) {
this.looper = looper;
}
private synchronized void stopLooper() {
if (looper == null) return;
looper.quit();
}
@Override
protected void runTask() {
final LocationManager locationManager = (LocationManager) service
.getSystemService(Context.LOCATION_SERVICE);
final SharedPreferences prefs = getPreferences();
final int maxPollingTime = Integer.parseInt(prefs.getString(
POLLING_KEY, "0"));
final int desiredAccuracy = Integer.parseInt(prefs.getString(
DESIRED_KEY, "0"));
final int acceptedAccuracy = Integer.parseInt(prefs.getString(
ACCEPTED_KEY, "0"));
final int maxAge = Integer.parseInt(prefs.getString(AGE_KEY, "0"));
final String whichProvider = prefs.getString(PROVIDER_KEY, "any");
final boolean canUseGps = whichProvider.equals("gps")
|| whichProvider.equals("any");
final boolean canUseNetwork = whichProvider.equals("network")
|| whichProvider.equals("any");
if (canUseNetwork)
networkEnabled = locationManager
.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (canUseGps)
gpsEnabled = locationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER);
// If any provider is enabled now and we displayed a notification clear it.
if (gpsEnabled || networkEnabled) removeErrorNotification();
if (gpsEnabled)
updateBestLocation(locationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER));
if (networkEnabled)
updateBestLocation(locationManager
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER));
if (desiredAccuracy == 0
|| getLocationQuality(desiredAccuracy, acceptedAccuracy,
maxAge, bestLocation) != LocationQuality.GOOD) {
// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
updateBestLocation(location);
if (desiredAccuracy != 0
&& getLocationQuality(desiredAccuracy,
acceptedAccuracy, maxAge, bestLocation)
== LocationQuality.GOOD)
stopLooper();
}
public void onProviderEnabled(String provider) {
if (isSameProvider(provider,
LocationManager.NETWORK_PROVIDER))networkEnabled =true;
else if (isSameProvider(provider,
LocationManager.GPS_PROVIDER)) gpsEnabled = true;
// The user has enabled a location, remove any error
// notification
if (canUseGps && gpsEnabled || canUseNetwork
&& networkEnabled) removeErrorNotification();
}
public void onProviderDisabled(String provider) {
if (isSameProvider(provider,
LocationManager.NETWORK_PROVIDER))networkEnabled=false;
else if (isSameProvider(provider,
LocationManager.GPS_PROVIDER)) gpsEnabled = false;
if (!gpsEnabled && !networkEnabled) {
showErrorNotification();
stopLooper();
}
}
public void onStatusChanged(String provider, int status,
Bundle extras) {
Log.i(LOG_TAG, "Provider " + provider + " statusChanged");
if (isSameProvider(provider,
LocationManager.NETWORK_PROVIDER)) networkEnabled =
status == LocationProvider.AVAILABLE
|| status == LocationProvider.TEMPORARILY_UNAVAILABLE;
else if (isSameProvider(provider,
LocationManager.GPS_PROVIDER))
gpsEnabled = status == LocationProvider.AVAILABLE
|| status == LocationProvider.TEMPORARILY_UNAVAILABLE;
// None of them are available, stop listening
if (!networkEnabled && !gpsEnabled) {
showErrorNotification();
stopLooper();
}
// The user has enabled a location, remove any error
// notification
else if (canUseGps && gpsEnabled || canUseNetwork
&& networkEnabled) removeErrorNotification();
}
};
if (networkEnabled || gpsEnabled) {
Looper.prepare();
setLooper(Looper.myLooper());
// Register the listener with the Location Manager to receive
// location updates
if (canUseGps)
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 1000, 1,
locationListener, Looper.myLooper());
if (canUseNetwork)
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 1000, 1,
locationListener, Looper.myLooper());
Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
stopLooper();
}
}, maxPollingTime * 1000);
Looper.loop();
t.cancel();
setLooper(null);
locationManager.removeUpdates(locationListener);
} else // No provider is enabled, show a notification
showErrorNotification();
}
if (getLocationQuality(desiredAccuracy, acceptedAccuracy, maxAge,
bestLocation) != LocationQuality.BAD) {
sendUpdate(new Event(EVENT_TYPE, locationToString(desiredAccuracy,
acceptedAccuracy, maxAge, bestLocation)));
} else Log.w(LOG_TAG, "LocationCollector failed to get a location");
}
private synchronized void showErrorNotification() {
if (notifId != 0) return;
ServiceHandler handler = service.getHandler();
NotificationInfo ni = NotificationInfo.createSingleNotification(
R.string.locationcollector_notif_ticker,
R.string.locationcollector_notif_title,
R.string.locationcollector_notif_text,
android.R.drawable.stat_notify_error);
Intent intent = new Intent(
android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
ni.pendingIntent = PendingIntent.getActivity(service, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
Message msg = handler.obtainMessage(ServiceHandler.SHOW_NOTIFICATION);
msg.obj = ni;
handler.sendMessage(msg);
notifId = ni.id;
}
private void removeErrorNotification() {
if (notifId == 0) return;
ServiceHandler handler = service.getHandler();
if (handler != null) {
Message msg = handler.obtainMessage(
ServiceHandler.CLEAR_NOTIFICATION, notifId, 0);
handler.sendMessage(msg);
notifId = 0;
}
}
@Override
public void interrupt() {
stopLooper();
super.interrupt();
}
private String locationToString(int desiredAccuracy, int acceptedAccuracy,
int maxAge, Location location) {
StringBuilder sb = new StringBuilder();
sb.append(String.format(
"qual=%s time=%d prov=%s acc=%.1f lat=%f long=%f",
getLocationQuality(desiredAccuracy, acceptedAccuracy, maxAge,
location), location.getTime() / 1000, // Millis to
// seconds
location.getProvider(), location.getAccuracy(), location
.getLatitude(), location.getLongitude()));
if (location.hasAltitude())
sb.append(String.format(" alt=%.1f", location.getAltitude()));
if (location.hasBearing())
sb.append(String.format(" bearing=%.2f", location.getBearing()));
return sb.toString();
}
private enum LocationQuality {
BAD, ACCEPTED, GOOD;
public String toString() {
if (this == GOOD) return "Good";
else if (this == ACCEPTED) return "Accepted";
else return "Bad";
}
}
private LocationQuality getLocationQuality(int desiredAccuracy,
int acceptedAccuracy, int maxAge, Location location) {
if (location == null) return LocationQuality.BAD;
if (!location.hasAccuracy()) return LocationQuality.BAD;
long currentTime = System.currentTimeMillis();
if (currentTime - location.getTime() < maxAge * 1000
&& location.getAccuracy() <= desiredAccuracy)
return LocationQuality.GOOD;
if (acceptedAccuracy == -1
|| location.getAccuracy() <= acceptedAccuracy)
return LocationQuality.ACCEPTED;
return LocationQuality.BAD;
}
private synchronized void updateBestLocation(Location location) {
bestLocation = getBestLocation(location, bestLocation);
}
protected Location getBestLocation(Location location,
Location currentBestLocation) {
if (currentBestLocation == null) {
// A new location is always better than no location
return location;
}
if (location == null) return currentBestLocation;
// Check whether the new location fix is newer or older
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
boolean isNewer = timeDelta > 0;
// If it's been more than two minutes since the current location, use
// the new location
// because the user has likely moved
if (isSignificantlyNewer) {
return location;
// If the new location is more than two minutes older, it must be
// worse
} else if (isSignificantlyOlder) {
return currentBestLocation;
}
// Check whether the new location fix is more or less accurate
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation
.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;
// Check if the old and new location are from the same provider
boolean isFromSameProvider = isSameProvider(location.getProvider(),
currentBestLocation.getProvider());
// Determine location quality using a combination of timeliness and
// accuracy
if (isMoreAccurate) {
return location;
} else if (isNewer && !isLessAccurate) {
return location;
} else if (isNewer && !isSignificantlyLessAccurate
&& isFromSameProvider) {
return location;
}
return bestLocation;
}
/** Checks whether two providers are the same */
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) return provider2 == null;
return provider1.equals(provider2);
}
Solution 5
Location accuracy depends mostly on the location provider used:
- GPS - will get you several meters accuracy (assuming you have GPS reception)
- Wifi - Will get you few hundred meters accuracy
- Cell Network - Will get you very inaccurate results (I've seen up to 4km deviation...)
If it's accuracy you are looking for, then GPS is your only option.
I've read a very informative article about it here.
As for the GPS timeout - 60 seconds should be sufficient, and in most cases even too much. I think 30 seconds is OK and sometimes even less than 5 sec...
if you only need a single location, I'd suggest that in your onLocationChanged
method, once you receive an update you'll unregister the listener and avoid unnecessary usage of the GPS.
Related videos on Youtube
Nicklas A.
Updated on August 13, 2020Comments
-
Nicklas A. almost 4 years
The problem:
Getting the user's current location within a threshold ASAP and at the same time conserve battery.
Why the problem is a problem:
First off, android has two providers; network and GPS. Sometimes network is better and sometimes the GPS is better.
By "better" I mean speed vs. accuracy ratio.
I'm willing to sacrifice a few meters in accuracy if I can get the location almost instant and without turning on the GPS.Secondly, if you request updates for location changes nothing is sent if the current location is stable.
Google has an example of determining the "best" location here: http://developer.android.com/guide/topics/location/obtaining-user-location.html#BestEstimate
But I think it's no where near as good as it should/could be.I'm kind of confused why google hasn't a normalized API for location, the developer shouldn't have to care where the location is from, you should just specify what you want and the phone should choose for you.
What I need help with:
I need to find a good way to determine the "best" location, maybe though some heuristic or maybe through some 3rd party library.
This does not mean determine the best provider!
I'm probably gonna use all providers and picking the best of them.Background of the app:
The app will collect the user's location at a fixed interval (let say every 10 minutes or so) and send it to a server.
The app should conserve as much battery as possible and the location should have X (50-100?) meters accuracy.The goal is to later be able to plot the user's path during the day on a map so I need sufficient accuracy for that.
Misc:
What do you think are reasonable values on desired and accepted accuracies?
I've been using 100m as accepted and 30m as desired, is this to much to ask?
I'd like to be able to plot the user's path on a map later.
Is 100m for desired and 500m for accepted better?Also, right now I have the GPS on for a maximum of 60 seconds per location update, is this too short to get a location if you're indoors with an accuracy of maybe 200m?
This is my current code, any feedback is appreciated (apart from the lack of error checking which is TODO):
protected void runTask() { final LocationManager locationManager = (LocationManager) context .getSystemService(Context.LOCATION_SERVICE); updateBestLocation(locationManager .getLastKnownLocation(LocationManager.GPS_PROVIDER)); updateBestLocation(locationManager .getLastKnownLocation(LocationManager.NETWORK_PROVIDER)); if (getLocationQuality(bestLocation) != LocationQuality.GOOD) { Looper.prepare(); setLooper(Looper.myLooper()); // Define a listener that responds to location updates LocationListener locationListener = new LocationListener() { public void onLocationChanged(Location location) { updateBestLocation(location); if (getLocationQuality(bestLocation) != LocationQuality.GOOD) return; // We're done Looper l = getLooper(); if (l != null) l.quit(); } public void onProviderEnabled(String provider) {} public void onProviderDisabled(String provider) {} public void onStatusChanged(String provider, int status, Bundle extras) { // TODO Auto-generated method stub Log.i("LocationCollector", "Fail"); Looper l = getLooper(); if (l != null) l.quit(); } }; // Register the listener with the Location Manager to receive // location updates locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 1000, 1, locationListener, Looper.myLooper()); locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 1000, 1, locationListener, Looper.myLooper()); Timer t = new Timer(); t.schedule(new TimerTask() { @Override public void run() { Looper l = getLooper(); if (l != null) l.quit(); // Log.i("LocationCollector", // "Stopping collector due to timeout"); } }, MAX_POLLING_TIME); Looper.loop(); t.cancel(); locationManager.removeUpdates(locationListener); setLooper(null); } if (getLocationQuality(bestLocation) != LocationQuality.BAD) sendUpdate(locationToString(bestLocation)); else Log.w("LocationCollector", "Failed to get a location"); } private enum LocationQuality { BAD, ACCEPTED, GOOD; public String toString() { if (this == GOOD) return "Good"; else if (this == ACCEPTED) return "Accepted"; else return "Bad"; } } private LocationQuality getLocationQuality(Location location) { if (location == null) return LocationQuality.BAD; if (!location.hasAccuracy()) return LocationQuality.BAD; long currentTime = System.currentTimeMillis(); if (currentTime - location.getTime() < MAX_AGE && location.getAccuracy() <= GOOD_ACCURACY) return LocationQuality.GOOD; if (location.getAccuracy() <= ACCEPTED_ACCURACY) return LocationQuality.ACCEPTED; return LocationQuality.BAD; } private synchronized void updateBestLocation(Location location) { bestLocation = getBestLocation(location, bestLocation); } // Pretty much an unmodified version of googles example protected Location getBestLocation(Location location, Location currentBestLocation) { if (currentBestLocation == null) { // A new location is always better than no location return location; } if (location == null) return currentBestLocation; // Check whether the new location fix is newer or older long timeDelta = location.getTime() - currentBestLocation.getTime(); boolean isSignificantlyNewer = timeDelta > TWO_MINUTES; boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES; boolean isNewer = timeDelta > 0; // If it's been more than two minutes since the current location, use // the new location // because the user has likely moved if (isSignificantlyNewer) { return location; // If the new location is more than two minutes older, it must be // worse } else if (isSignificantlyOlder) { return currentBestLocation; } // Check whether the new location fix is more or less accurate int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation .getAccuracy()); boolean isLessAccurate = accuracyDelta > 0; boolean isMoreAccurate = accuracyDelta < 0; boolean isSignificantlyLessAccurate = accuracyDelta > 200; // Check if the old and new location are from the same provider boolean isFromSameProvider = isSameProvider(location.getProvider(), currentBestLocation.getProvider()); // Determine location quality using a combination of timeliness and // accuracy if (isMoreAccurate) { return location; } else if (isNewer && !isLessAccurate) { return location; } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) { return location; } return bestLocation; } /** Checks whether two providers are the same */ private boolean isSameProvider(String provider1, String provider2) { if (provider1 == null) { return provider2 == null; } return provider1.equals(provider2); }
-
Matthew almost 11 yearsChiming in really late, but the "Fused Location Provider" that was recently announced at IO 2013 looks like it addresses many of your needs -- developer.android.com/google/play-services/location.html
-
Gavriel over 9 yearsshouldn't the last line of getBestLocation() be: return currentBestLocation; instead of return bestLocation;?
-
-
Nicklas A. almost 13 yearsYeah, but I the problem comes if the lastKnownLocation is really bad. I need a good way of deciding the best of two locations.
-
Aleadam almost 13 yearsYou can store the towers info and check if those towers changed. If they did, then wait for a new location, if not (or if only some changed), then reuse it. That way you avoid comparing the tower locations to a database.
-
Nicklas A. almost 13 yearsUsing towers seems like a big overkill to me, good idea though.
-
Aleadam almost 13 years@Nicklas the code does not get any more complicated than that. You will need android.Manifest.permission#ACCESS_COARSE_UPDATES, though.
-
Nicklas A. almost 13 yearsYeah, but I still need to use a third party service and also I need a way to decide when to user the tower info over the location data, this just add an extra layer of complexity.
-
Nicklas A. almost 13 yearsAh, I see. Well, the location will probably be fetched every 10 minutes or so, then it seems kinda weird that you need to wait 10 minutes for a location
-
Aleadam almost 13 years@Nicklas you don't. I based that time in what you said above. If you keep listening in the background, you can use requestLocationUpdates(...), to set up the time span you want (even 1 second), but that would force the phone to stay awake for that.
-
Nicklas A. almost 13 yearsI don't really care from where I get my location, I don't want to limit me to one provider
-
Muzikant almost 13 yearsYou can register all location providers available on the device (you can get the list of all providers from LocationManager.getProviders()), but if you are looking for an accurate fix, in most cases the network provider will not be useful for you.
-
Nicklas A. almost 13 yearsYou never actually get a fresh location, you only use locations that happens to be there from previous updates. I think this code would benefit greatly by actually adding a listener that updates the location by turning on the GPS from time to time.
-
Nicklas A. almost 13 yearsI've looked into
Criteria
but what if the latest network location is awesome (it might know through wifi) and it takes no time or battery to get it (getLastKnown), then criteria will probably disregard that and return the GPS instead. I can't believe google has made it this difficult for developers. -
Nicklas A. almost 13 yearsYeah, but this does is not a question about choose between providers, this is a question about getting the best location generally (even when there is multiple providers involved)
-
Nicklas A. almost 13 yearsInteresting indeed, they only seem to use WiFi however which is very nice but I still need it to work when there is no wifi or 3G/2G connection around so this would be adding another layer of abstraction. Good catch though.
-
Gryphius almost 13 yearssorry, I thought you were only interested in the part that selects the best from all available locations. I added the code above that requests these as well. if a new gps location is received, it is stored/uploaded right away. if I receive a network location update I store it for reference and 'hope' that I'll receive a gps update as well until the next location check happens.
-
Ed Burnette almost 13 yearsSkyhook appears to use a combination of WiFi, GPS, and cell towers. See skyhookwireless.com/howitworks for the technical details. They have gotten several design wins lately, for example Mapquest, Twydroid, ShopSavvy, and the Sony NGP. Note that downloading and trying out their SDK appears to be free but you have to contact them about a license for distributing it in your app. Unfortunately they don't list the price on their web site.
-
Nicklas A. almost 13 yearsOh, I see. Well, if it isn't free to use commercially then I'm afraid I cannot use it.
-
Nicklas A. almost 13 yearsWell, it isn't important that it's the very best, just that it's good enough to plot on a map and that I don't drain the battery since this is a background task.
-
Stéphane almost 13 yearsOn top of using the Criteria, you could, at each location update sent by the provider you selected, check the lastKnowLocation for the GPS provider and compare it (accuracy and date) to your current location. But this seems to me a nice-to-have rather than a requirement from your specifications ; if somewhat better accuracy is sometimes achieved, will it really be useful to your users?
-
Nicklas A. almost 13 yearsThat is what I'm doing now, the problem is I have a hard time figuring out if the last know is good enough. I can also add that I don't have to limit myself to one provider, the more I use the faster I might get a lock.
-
Nicklas A. almost 13 yearsEven though this does not directly answer my question it is the most related answer, therefor I'm awarding you the bounty, thanks for your help!
-
Eduardo about 12 yearsHave in mind that PASSIVE_PROVIDER requires API Level 8 or higher.
-
School Boy about 12 yearsHi Nicklas i have same equirement so could i communicate to you by any means.. i would be thank full to you if you could helps us..
-
Diego over 11 years@Gryphius, you have a startRecording() method, but how do I stop all the updates?
-
Gryphius over 11 yearsI also had a stopRecording() method which cancelled the timer. I eventually switched from a timer to a ScheduledThreadPoolExecutor, so stopRecording now basically calls executor.shutdown() and de-registers all location update listeners
-
Diego over 11 yearsI tried to cancel de gpsTimer.cancel(), but the listeners, updating. I think I need to call locationManager.removeUpdates, but which Listeners do I cancel, do you still have the stopRecording() method? Could you add that to your answer? Thanks a lot!
-
Gryphius over 11 yearsaccording to my scm, stopRecording only called gpsTimer.cancel() and set gps_recorder_running=false, so like in your case, no cleanup of the listeners back then. the current code keeps track of all active listeners in a vector, I didn't have this when I wrote this answer 1.5 years ago.
-
Radu about 11 years"and if there are no thick walls around." - even fiber glass can make GPS not fix a location...
-
Gaucho about 11 years@Stéphane sorry for the edit. Don't take care of it. Your post is correct. I did that edit for error. Sorry. Regards.
-
Stéphane about 11 years@Gaucho I actually don't see an edit, I guess you have reversed it... Anyway no worries, and thanks for the review.
-
M4rk about 10 yearsCould you post anywhere (github, pastebin), the whole class? Really appreciated
-
M4rk about 10 yearsCould you post the whole code? Thanks, really appreciated
-
Gryphius about 10 yearsit is already on github, but I'm not sure this is still the best way to do GPS stuff nowadays. Afaik they have made many improvements to the location API since I wrote this code.
-
Nicklas A. about 10 yearsThat is all of the code. I don't have access to the project any more.
-
Firas Al Mannaa almost 10 yearsthanks for this great example ... one question, what is this method
getGPSCheckMilliSecsFromPrefs();
? @Gryphius -
Gryphius almost 10 yearsthis returns the (user configurable) location check interval in milliseconds. smaller amount means requesting the location more often -> higher accuracy for gps tracks but faster battery drain
-
Nezam almost 10 years
add a 'minimum distance to last known location' check. without this, your points will "jump around"
:: can you tell us how to achieve this? this is exactly the problem i am facing right now. -
Gryphius almost 10 yearsit's in the code above. the minimum distance is a configuration setting :
long minDistance = getMinDistanceFromPrefs();
, and then further downif (l.distanceTo(lastLocation) < minDistance...
-
Nezam almost 10 yearswhen and how often should
startRecording
be called ? Basically i am plotting currentlocation inOnResume
? -
Gödel77 over 9 yearsYou seem to have taken the code of this project "android-protips-location" and it's still alive. People can see how it works here code.google.com/p/android-protips-location/source/browse/trunk/…
-
S.M_Emamian about 9 yearsI think that using Place API is the best way. developers.google.com/places/training
-
jean d'arme about 9 yearsWould it work with this problem? stackoverflow.com/questions/30236136/…
-
Admin over 8 yearsHow I can get lat/lon ?
-
C0D3 over 8 yearsWhere do you get the isProvidedSupported function? Sorry, I'm new to android
-
Gryphius over 8 years@c0d3Junk13 you'll find this method in the github source I've linked in an earlier comment.
-
Narendra Singh almost 8 years@Gryphius where is getGPSCheckMilliSecsFromPrefs?
-
dhami_ji over 6 yearsI am from future according to this question asked date , my question is does getBearing() will work with your code, bcoz i have seen many answers saying that network providers will give poor accuracy of getBearing().
-
Nouman Ch over 6 yearsgetGPSCheckMilliSecsFromPrefs() post this method plz