Le problème:
L'obtention de l'utilisateur de l'emplacement actuel à l'intérieur d'un seuil le plus tôt possible et en même temps économiser la batterie.
Pourquoi le problème est un problème:
Tout d'abord, android a deux fournisseurs de réseau et GPS. Parfois, le réseau est le meilleur et parfois le GPS est mieux.
Par "mieux", je veux dire de la vitesse par rapport à l'exactitude ratio.
Je suis prêt à sacrifier quelques mètres en précision si je peux obtenir l'emplacement de presque instantané et sans avoir à allumer le GPS.
Deuxièmement, si vous demander les mises à jour pour les modifications de l'emplacement, rien n'est envoyé si la position actuelle est stable.
Google est un exemple de déterminer le "meilleur" emplacement ici: http://developer.android.com/guide/topics/location/obtaining-user-location.html#BestEstimate
Mais je pense que c'est pas loin d'être aussi bon qu'il devrait ou pourrait être.
Je suis un peu confus pourquoi google n'a pas normalisée de l'API pour l'emplacement, le développeur ne devrait pas avoir à faire de l'endroit où l'emplacement est à partir, vous devez simplement spécifier ce que vous voulez et le téléphone devrait choisir pour vous.
Ce que j'ai besoin d'aide:
J'ai besoin de trouver une bonne façon de déterminer le "meilleur" emplacement, peut-être bien que certains heuristique ou peut-être grâce à quelques la 3e partie de la bibliothèque.
Cela ne signifie pas déterminer le meilleur fournisseur!
Je suis probablement va utiliser tous les fournisseurs et choisir le meilleur d'entre eux.
Arrière-plan de l'application:
L'application permettra de recueillir la position de l'utilisateur à un intervalle fixe (disons toutes les 10 minutes) et de l'envoyer à un serveur.
L'application doit conserver autant de batterie que possible et l'emplacement doit avoir X (50-100?) mètres de précision.
L'objectif est pour plus tard être en mesure de tracer le chemin d'accès de l'utilisateur au cours de la journée, sur une carte, donc j'ai besoin d'une précision suffisante pour que.
Divers:
Que pensez-vous des valeurs raisonnables souhaité et accepté des précisions?
J'ai été en utilisant 100m comme acceptée et 30m en tant désiré, est-ce trop demander?
J'aimerais être capable de tracer le chemin d'accès de l'utilisateur sur une carte plus tard.
Est à 100m de désiré et 500 m pour le mieux accepté?
Aussi, en ce moment j'ai le GPS sur pour un maximum de 60 secondes par emplacement de mise à jour, est-ce trop courte pour obtenir un emplacement, si vous êtes à l'intérieur avec une précision de peut-être 200 m?
C'est mon code actuel, tout commentaire est apprécié (à l'exception de l'absence de vérification d'erreur qui est à faire):
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);
}