Potrzebuję napisać aplikację, która co 5 minut określa aktualną lokalizację telefonu komórkowego (przy użyciu wszystkich wolnych, dostępnych dostawców lokalizacji) i wysyła go na serwer.Jak na bieżąco śledzić lokalizację telefonu komórkowego z systemem Android?
Jeśli jakiś dostawca lokalizacji nie działa na początku aplikacji, ale staje się dostępny później, aplikacja powinna również przetworzyć swoje dane o lokalizacji.
W tym celu zaimplementowałem następujące klasy. W jednej z moich czynności tworzę jego instancję i wywołuję jej metodę startTrackingUpdates
. locationChangeHandler
przetwarza dane lokalizacji.
public class LocationTracker implements ILocationTracker, LocationListener {
public static final long MIN_TIME_BETWEEN_UPDATES = 1000 * 60 * 5; // 5 minutes
public static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
private ILocationManager locationManager;
private ILocationChangeHandler locationChangeHandler;
public LocationTracker(final ILocationManager aLocationManager,
final ILocationChangeHandler aLocationChangeHandler) {
this.locationManager = aLocationManager;
this.locationChangeHandler = aLocationChangeHandler;
}
public void startTrackingUpdates() {
final List<String> providers = locationManager.getAllProviders();
for (final String curProviderName : providers)
{
final ILocationProvider provider = locationManager.getLocationProvider(curProviderName);
if (!provider.hasMonetaryCost())
{
subscribeToLocationChanges(provider);
}
}
}
private void subscribeToLocationChanges(final ILocationProvider aProvider) {
locationManager.requestLocationUpdates(aProvider.getName(), MIN_TIME_BETWEEN_UPDATES,
(float)MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
}
public void onLocationChanged(final Location aLocation) {
locationChangeHandler.processLocationChange(new LocationWrapper(aLocation));
}
public void onProviderDisabled(final String aProvider) {
}
public void onProviderEnabled(final String aProvider) {
}
public void onStatusChanged(final String aProvider, final int aStatus,
final Bundle aExtras) {
}
}
Zbudowałem aplikację i zainstalowałem ją na moim telefonie komórkowym. Rano wziąłem telefon, poszedłem do pracy, a potem wróciłem do domu. W domu sprawdziłem wyniki całodziennej pracy aplikacji i znalazłem tylko jeden rekord w bazie danych.
Pod warunkiem, że reszta systemu (transmisja danych lokalizacji na serwer, zapisywanie w bazie danych) działa poprawnie, muszę mieć pewien problem w kodzie śledzenia lokalizacji (onLocationChanged
nie został wywołany, mimo że zmieniłem swoją lokalizację kilka razy).
Co jest nie tak z moim kodem (w jaki sposób powinienem go zmienić, aby wywołać onLocationChanged
, gdy lokalizacja telefonu zmieni się o więcej niż MIN_DISTANCE_CHANGE_FOR_UPDATES
metrów według jednego z lokalizatorów)?
Update 1 (18.08.2013 13:59 MSK):
zmieniłem kod według msh zaleceń. I uruchomić stoper przy użyciu następującego kodu:
public void startSavingGeoData() {
final IAlarmManager alarmManager = activity.getAlarmManager();
final IPendingIntent pendingIntent = activity.createPendingResult(
ALARM_ID, intentFactory.createEmptyIntent(), 0);
alarmManager.setRepeating(INTERVAL, pendingIntent);
}
W activity
kładę następujące procedury obsługi zdarzenia Timer:
@Override
protected void onActivityResult(final int aRequestCode, final int aResultCode,
final Intent aData) {
geoDataSender.processOnActivityResult(aRequestCode, aResultCode,
new IntentWrapper(aData));
}
Gdy telefon jest włączony, wszystko działa zgodnie z oczekiwaniami - onActivityResult
jest wykonywany raz w INTERVAL
milisekundy.
Ale kiedy naciskam przycisk zasilania (ekran staje się nieaktywny), onActivityResult
nie jest w ogóle wywoływany. Po ponownym naciśnięciu przycisku zasilania onActivityResult
jest wykonywany tyle razy, co INTERVAL
od czasu, kiedy wyłączyłem telefon. Jeśli wyłączyłem telefon na 1 * INTERVAL
milisekund, uruchomi się on raz. Jeśli wyłączyłem telefon na 2 * INTERVAL
milisekund, uruchomi się on dwukrotnie itd.
Uwaga: "wyłączając" mam na myśli krótkie naciśnięcie przycisku zasilania (telefon nadal "żyje" i reaguje na przychodzące SMS-y, przykład).
Jak zmodyfikować kod startSavingGeoData
, aby metoda onActivityResult
była wykonywana comilisekund, nawet jeśli telefon się przesypia?
Update 2 (18.08.2013 19:29 MSK): Ani alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 0, INTERVAL, pendingIntent)
, ani alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, INTERVAL, INTERVAL, pendingIntent)
rozwiązało problem.
Typ alarmu musi być jedną ze stałych _WAKEUP, na przykład RTC_WAKEUP – msh
@msh Zobacz aktualizację 2. –
Wypróbuj http://stackoverflow.com/questions/4459058/alarm-manager-example pierwszy - jeśli działa, bazuj na to. Zwróć uwagę, że zachowuje on tylko funkcję wakelock do momentu powrotu onReceive, jeśli musisz pracować dłużej - uzyskaj własne – msh