Mi aplicación necesita soluciones de ubicación de manera regular, incluso cuando el teléfono no está activo. Para hacer esto, estoy usando IntentService con el patrón proporcionado generosamente por Commonsware. https://github.com/commonsguy/cwac-wakefulEnviando un mensaje a un controlador sobre un hilo inactivo al obtener una ubicación de un servicio de intención
Para obtener soluciones de ubicación, confío en el siguiente código proporcionado por un miembro llamado Fedor. What is the simplest and most robust way to get the user's current location on Android?. Lo modifiqué ligeramente para que devuelva nulo en lugar de obtener la última ubicación conocida
Ambos funcionan perfectamente bien cuando no se combinan: Puedo obtener una corrección de ubicación de la clase de Fedor en una Actividad, y puedo hacer algunas cosas básicas (como registrar algo) usando la clase de Commonsware.
El problema se produce cuando intento solucionar problemas de ubicación de la subclase WakefulIntentService de Commonsware. Los LocationListeners no reaccionan a LocationUpdates y recibo estas advertencias (todavía no conozco las sutilezas de los hilos, los manipuladores, ...). ¿Alguien puede ayudarme a entender cuál es el problema? Gracias y les deseo a todos un muy feliz año nuevo :)
12-31 14:09:33.664: W/MessageQueue(3264): Handler (android.location.LocationManager$ListenerTransport$1) {41403330} sending message to a Handler on a dead thread
12-31 14:09:33.664: W/MessageQueue(3264): java.lang.RuntimeException: Handler (android.location.LocationManager$ListenerTransport$1) {41403330} sending message to a Handler on a dead thread
12-31 14:09:33.664: W/MessageQueue(3264): at android.os.MessageQueue.enqueueMessage(MessageQueue.java:196)
12-31 14:09:33.664: W/MessageQueue(3264): at android.os.Handler.sendMessageAtTime(Handler.java:473)
12-31 14:09:33.664: W/MessageQueue(3264): at android.os.Handler.sendMessageDelayed(Handler.java:446)
12-31 14:09:33.664: W/MessageQueue(3264): at android.os.Handler.sendMessage(Handler.java:383)
12-31 14:09:33.664: W/MessageQueue(3264): at android.location.LocationManager$ListenerTransport.onLocationChanged(LocationManager.java:193)
12-31 14:09:33.664: W/MessageQueue(3264): at android.location.ILocationListener$Stub.onTransact(ILocationListener.java:58)
12-31 14:09:33.664: W/MessageQueue(3264): at android.os.Binder.execTransact(Binder.java:338)
12-31 14:09:33.664: W/MessageQueue(3264): at dalvik.system.NativeStart.run(Native Method)
Ésta es mi WakefulIntentService subclase:
public class AppService extends WakefulIntentService {
public static final String TAG = "AppService";
public AppService() {
super("AppService");
}
public LocationResult locationResult = new LocationResult() {
@Override
public void gotLocation(final Location location) {
if (location == null)
Log.d(TAG, "location could not be retrieved");
else
sendMessage(location);
}
};
@Override
protected void doWakefulWork(Intent intent) {
PhoneLocation myLocation;
myLocation = new PhoneLocation();
myLocation.getLocation(getApplicationContext(), locationResult);
}
Y aquí una copia de la clase de Fedor (ligeramente modificado: no hay necesidad de GPS ni el último ubicación conocida)
public class PhoneLocation {
public static String TAG = "MyLocation";
Timer timer1;
LocationManager lm;
LocationResult locationResult;
boolean gps_enabled=false;
boolean network_enabled=false;
public boolean getLocation(Context context, LocationResult result)
{
//I use LocationResult callback class to pass location value from MyLocation to user code.
locationResult=result;
if(lm==null) lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
//exceptions will be thrown if provider is not permitted.
try{gps_enabled=lm.isProviderEnabled(LocationManager.GPS_PROVIDER);}catch(Exception ex){}
try{network_enabled=lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);}catch(Exception ex){}
//don't start listeners if no provider is enabled
if(!gps_enabled && !network_enabled)
return false;
if(network_enabled) lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
timer1=new Timer();
timer1.schedule(new ReturnNullLocation(), 20000);
return true;
}
LocationListener locationListenerNetwork = new LocationListener() {
public void onLocationChanged(Location location) {
timer1.cancel();
locationResult.gotLocation(location);
lm.removeUpdates(this);
}
public void onProviderDisabled(String provider) {}
public void onProviderEnabled(String provider) {}
public void onStatusChanged(String provider, int status, Bundle extras) {}
};
class ReturnNullLocation extends TimerTask {
@Override
public void run() {
lm.removeUpdates(locationListenerNetwork);
locationResult.gotLocation(null);
}
}
public static abstract class LocationResult{
public abstract void gotLocation(Location location);
}
}
Funciona como un encanto! Muchas gracias! He configurado la alarma en mi subclase de aplicación y he creado los métodos startLocationPoll() y stopLocationPoll() allí. ¡Feliz año nuevo! – znat
cuando uso el ejemplo en el enlace ... tengo ... "E/LocationPoller (442): Invalid Intent - no tiene proveedor" ... ¿alguna pista, por favor? – user836026
@ user836026: No proporcionó el 'LocationPoller.EXTRA_PROVIDER' adicional en el' Intent', indicando qué proveedor usar. Si tiene preguntas adicionales sobre este componente, utilice el botón "Preguntar", en lugar de publicar comentarios aquí. – CommonsWare