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.