2013-08-15 19 views
9

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.

+0

Typ alarmu musi być jedną ze stałych _WAKEUP, na przykład RTC_WAKEUP – msh

+0

@msh Zobacz aktualizację 2. –

+0

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

Odpowiedz

8

Twój kod jest prawdopodobnie poprawny, ale dostawcy lokalizacji nie działają, gdy Twój telefon śpi.Konieczne może być nabycie wakelocku (jeśli nie zależy Ci na poborze mocy) lub skorzystanie z Menedżera alarmów i zaplanowanie, aby aplikacja przebudziła się i okresowo sprawdzała lokalizację (nadal musisz mieć aktywny wakelock podczas oczekiwania na aktualizację, albo nabyte przez AlamManager lub własne).

+0

Zmieniłem kod (patrz "Aktualizacja 1"), ale nadal nie działa zgodnie z oczekiwaniami. Jakieś pomysły? –

+0

Można podać kod alarmu na tym przykładzie http://stackoverflow.com/questions/4459058/alarm-manager-example – msh

+0

Tak, ten przykład działa, przynajmniej metoda uzyskania lokalizacji jest wykonywana nawet, gdy telefon śpi. –

Powiązane problemy