Como rastrear continuamente a localização de um celular Android?

Preciso escrever um aplicativo, que a cada 5 minutos determina a localização atual do celular (usando todos os provedores de localização disponíveis e gratuitos) e o envia para um servidor.

Se algum provedor de localização não funcionar no início do aplicativo, mas se tornar disponível posteriormente, o aplicativo também deverá processar seus dados de localização.

Para fazer isso, eu implementei a seguinte classe. Em uma das minhas atividades, eu crio uma instância dela e chamo a suastartTrackingUpdates método.locationChangeHandler faz o processamento de dados de localização.

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) {
    }
}

Eu construí o aplicativo e instalei no meu celular. Então, de manhã, peguei meu telefone, fui trabalhar e voltei para casa. Em casa, verifiquei os resultados de um dia inteiro de trabalho do aplicativo e encontrei apenas um registro no banco de dados.

Desde que o resto do sistema (transmissão de dados de localização para o servidor, salvando no banco de dados) funcione corretamente, eu devo ter algum problema no código de rastreamento de localização (onLocationChanged não foi invocado, embora eu mudei a minha localização várias vezes).

O que há de errado com o meu código (como devo alterá-lo, para que oonLocationChanged para ser chamado sempre que a localização do telefone mudar por mais deMIN_DISTANCE_CHANGE_FOR_UPDATES metros de acordo com um dos prestadores locatin)?

Atualização 1 (18.08.2013 13:59 MSK):

Eu mudei meu código de acordo commsh recomendações. Eu começo o timer usando o seguinte código:

public void startSavingGeoData() {
    final IAlarmManager alarmManager = activity.getAlarmManager();
    final IPendingIntent pendingIntent = activity.createPendingResult(
            ALARM_ID, intentFactory.createEmptyIntent(), 0);
    alarmManager.setRepeating(INTERVAL, pendingIntent);
}

Noactivity Eu coloquei seguinte manipulador de eventos do temporizador:

@Override
protected void onActivityResult(final int aRequestCode, final int aResultCode, 
        final Intent aData) {
    geoDataSender.processOnActivityResult(aRequestCode, aResultCode, 
            new IntentWrapper(aData));
}

Quando o telefone está ligado, tudo funciona como esperado -onActivityResult é executado uma vez emINTERVAL milissegundos.

Mas quando pressiono o botão liga / desliga (a tela fica desabilitada),onActivityResult não é invocado a todos. Quando eu pressionar o botão de energia novamente,onActivityResult é executado quantas vezes,INTERVAL passou desde o momento em que desliguei o telefone. Se eu desliguei o telefone por1 * INTERVAL milissegundos, ele irá disparar uma vez. Se eu desliguei o telefone por2 * INTERVAL milissegundos, vai disparar duas vezes etc.

Nota: Ao "desligar" eu quero dizer uma pressão curta do botão de energia (o telefone ainda "vive" e reage ao SMS recebido, por exemplo).

Como devo modificar o código destartSavingGeoData para que o métodoonActivityResult para ser executado a cadaINTERVAL milissegundos, mesmo quando o telefone dorme?

Atualização 2 (18.08.2013 19:29 MSK): NemalarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 0, INTERVAL, pendingIntent)nemalarmManager.setRepeating(AlarmManager.RTC_WAKEUP, INTERVAL, INTERVAL, pendingIntent) resolveu o problema.

questionAnswers(1)

yourAnswerToTheQuestion