Enviar extra a requestLocationUpdates intentService rompe las actualizaciones de ubicación
Tengo problemas para enviar una cadena extra con mi PendingIntent
que paso a LocationServices.FusedLocationApi.requestLocationUpdates(GoogleApiClient client, LocationRequest request, PendingIntent callbackIntent)
.
Parece que el nombre de usuario extra que estoy poniendo en el Intent
es mangling la ubicación que requestLocationUpdates
está tratando de entregar a mi IntentService
como intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED)
devuelve null
.
- Servicio de Android con la ubicación de los servicios de Google Play que hace que la aplicación se abra al azar
- Uso de Proguard para eliminar clases no utilizadas en la biblioteca de Servicios de Google Play
- Error: El atributo "theme" ya ha sido definido
- Google Play Services 9.2.0 clases perdidas
- App Invites for Android: Cómo configurar el contenido de los mensajes recibidos
EDITAR
He intentado hacer una clase de User
que implementa Parcelable
y ponerlo como un extra:
mRequestLocationUpdatesIntent.putExtra("username", new User(username));
Y también he intentado poner el Parcelable User
dentro de un Bundle
como se sugiere a través de un comentario en este informe de errores https://code.google.com/p/android/issues/detail?id=81812 :
Bundle userBundle = new Bundle(); userBundle.putParcelable("user", new User(username)); mRequestLocationUpdatesIntent.putExtra("user", userBundle);
En mi servicio
Bundle userBundle = intent.getBundleExtra("user"); User user = userBundle.getParcelable("user"); String username = user.getUsername();
Sin embargo, ninguno de estos enfoques ha hecho ninguna diferencia. Siempre que pongo algún extra en mi intención, la ubicación nunca se agrega a la intención cuando se producen las actualizaciones.
He configurado este IntentService
para manejar las actualizaciones de ubicación:
public class LocationUpdateService extends IntentService { private final String TAG = "LocationUpdateService"; public LocationUpdateService() { super("LocationUpdateService"); } @Override protected void onHandleIntent(Intent intent) { Log.d(TAG, "onHandleIntent"); Bundle extras = intent.getExtras(); Log.d(TAG, "keys found inside intent: " + TextUtils.join(", ", extras.keySet())); String username = intent.getStringExtra("username"); if (username != null) { Log.d(TAG, "username: " + username); } else { Log.d(TAG, "username: null"); } if (!intent.hasExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED)) { Log.d(TAG, "intent does not have location :("); } Location location = intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED); if (location == null) { Log.d(TAG, "location == null :("); } Log.d(TAG, "latitude " + String.valueOf(location.getLatitude())); Log.d(TAG, "longitude " + String.valueOf(location.getLongitude())); ... } }
Cuando el usuario hace clic en un botón, startLocationUpdates
se llama en mi actividad principal:
Clase de actividad principal:
... Boolean mLocationUpdatesEnabled = false; protected void createLocationRequest() { mLocationRequest = new LocationRequest(); mLocationRequest.setInterval(LOCATION_UPDATE_INTERVAL); mLocationRequest.setFastestInterval(LOCATION_UPDATE_FASTEST_INTERVAL); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); } protected void startLocationUpdates() { Log.d(TAG, "startng location updates..."); mLocationUpdatesEnabled = true; if (mLocationRequest == null) { createLocationRequest(); } // create the Intent to use WebViewActivity to handle results Intent mRequestLocationUpdatesIntent = new Intent(this, LocationUpdateService.class); // create a PendingIntent mRequestLocationUpdatesPendingIntent = PendingIntent.getService(getApplicationContext(), 0, mRequestLocationUpdatesIntent, PendingIntent.FLAG_CANCEL_CURRENT); // request location updates LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mRequestLocationUpdatesPendingIntent); Log.d(TAG, "location updates started"); } protected void stopLocationUpdates() { Log.d(TAG, "stopping location updates..."); mLocationUpdatesEnabled = false; LocationServices.FusedLocationApi.removeLocationUpdates( mGoogleApiClient, mRequestLocationUpdatesPendingIntent); Log.d(TAG, "location updates stopped"); }
Todo esto funciona bien y bien; Cuando el usuario presiona el botón, toggleLocationUpdates
se llama, que llama LocationServices.FusedLocationApi.requestLocationUpdates
que llama a mi LocationUpdateService
donde puedo obtener la ubicación.
El problema viene cuando intenté poner una cadena extra en mi Intent
usando Intent.putExtra (String, String):
Clase de actividad principal:
... protected void startLocationUpdates(String username) { .... // create the Intent to use WebViewActivity to handle results Intent mRequestLocationUpdatesIntent = new Intent(this, LocationUpdateService.class); ////////////////////////////////////////////////////////////////// // // When I put this extra, IntentService sees my username extra // but the parcelableExtra `location` == null :( // ////////////////////////////////////////////////////////////////// mRequestLocationUpdatesIntent.putExtra("username", username); ... } ...
EDIT Yo había comenzado la siguiente oración como una declaración en lugar de una pregunta: "Estoy usando …"
¿Estoy usando el método correcto para enviar algunos datos adicionales a esta ubicación? Actualizar el manejo de IntentService
o hay una manera más sana de hacer esto?
¿Es esto un error o simplemente mala documentación?
- Cómo configurar el modo photosphere cuando se abra panorama Android
- ¿Cómo capturar los valores de los códigos de barras con la nueva API de código de barras en Google Play Services?
- Extraño accidente con los últimos servicios de Google Play
- Google login obtiene token de acceso con GoogleSignInOptions nuevo
- Tamaño de vista previa para el escáner de código de barras de la visión api
- Google AppInvite: el correo electrónico no se envía mientras SMS se envía
- Error al agregar geofences en Android (código de estado 1000)
- Código de estado 12501 autenticando con inicio de sesión de Google
El uso de IntentService junto con FusedLocationProviderAPI presentará problemas. En los Documentos del desarrollador titulados Actualizaciones de la ubicación de recepción :
Dependiendo de la forma de la solicitud, el proveedor de ubicación fusionado invoca el método de devolución de llamada
LocationListener.onLocationChanged()
y lo pasa un objeto Location o emite unPendingIntent
que contiene la ubicación en sus datos extendidos. La precisión y frecuencia de las actualizaciones se ven afectadas por los permisos de ubicación que ha solicitado y las opciones que ha establecido en el objeto de solicitud de ubicación
Además, un PendingIntent
se utiliza para extender permisos para otro código ( FusedLocationProviderAPI
en Google Play Services) para ejecutar su código dentro de su apk. Un IntentService
se utiliza para iniciar un servicio definido dentro del ámbito de su apk.
Por lo tanto, el método requiere una implementación de LocationListener
para las actualizaciones de primer plano, o un PendingIntent
para las actualizaciones de fondo junto con un Broadcast Receiver.
Este es un ejemplo de trabajo de algunos métodos utilizados para solicitar actualizaciones de ubicación de un PendingIntent
junto con valores adicionales.
Nota: LocalStorage.java
es una clase de utilidad para almacenar variables locales, no forma parte de la API de Android
GPSPlotter
/** * Private helper method to initialize the Google Api Client with the * LocationServices Api and Build it for use. */ private void initializeGoogleApiClient() { mGoogleApiClient = new GoogleApiClient.Builder(mContext) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); } /** * Private helper method to determine whether or not GooglePlayServices * are installed on the local system. * * @return services are installed. */ private boolean googlePlayServicesInstalled() { int result = GooglePlayServicesUtil.isGooglePlayServicesAvailable(mContext); return result == ConnectionResult.SUCCESS; } /** * Private method to build the Api Client for use with the LocationServices API. */ private synchronized void buildApiClient() { Log.w(TAG, "Building Google Api Client..."); initializeGoogleApiClient(); } /** * Private method used to connect the ApiClient to the Api hosted by Google for * Accessing Locations. */ private void connectClient() { mGoogleApiClient.connect(); } /** * User passes in a requested interval polling time in seconds as an * integer. * * @param theAccount is a reference to the parent activity used for updating views. */ public void beginManagedLocationRequests(MyAccount theAccount) { if (mAccount == null) mAccount = theAccount; startBackgroundUpdates(); } /** * Public method to end the managed Location Requests. */ public void endManagedLocationRequests() { endBackgroundUpdates(); } /** * This method handles the switch in polling rates by stopping and then starting once more the * background udpates, which in turn sets the interval in another method in the call stack. * @param theInterval the desired interval polling rate */ public void changeRequestIntervals(int theInterval) { mIntentInterval = theInterval; if (LocalStorage.getRequestingBackgroundStatus(mContext)) { endBackgroundUpdates(); startBackgroundUpdates(); } } /** * Private helper method to build an Intent that will be couple with a pending intent uses * for issuing background Location requests. * * @return theIntent */ private Intent buildBackgroundRequestIntent() { Intent intent = new Intent(mContext, BackgroundLocationReceiver.class); intent.setAction(BACKGROUND_ACTION); intent.putExtra(User.USER_ID, mUserID); return intent; } /** * Private helper method used to generate a PendingIntent for use when the User requests background service * within the FusedLocationApi until the Interval is changed. * * @return pendingIntent */ private PendingIntent buildRequestPendingIntent(Intent theIntent) { Log.w(TAG, "building pending intent"); return PendingIntent.getBroadcast(mContext, 0, theIntent, 0); } /** * Private method to start the Location Updates using the FusedLocation API in the background. */ private void startBackgroundUpdates() { Log.w(TAG, "Starting background updates"); if (googlePlayServicesInstalled()) { LocalStorage.putBackgroundRequestStatus(true, mContext); LocalStorage.putLocationRequestStatus(true, mContext); registerAlarmManager(); LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, buildLocationRequest(), buildRequestPendingIntent(buildBackgroundRequestIntent())); } } /** * Private method to end background updates. */ private void endBackgroundUpdates() { Log.w(TAG, "Ending background updates"); LocalStorage.putBackgroundRequestStatus(false, mContext); LocalStorage.putLocationRequestStatus(false, mContext); unregisterAlarmManager(); LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, buildRequestPendingIntent(buildBackgroundRequestIntent())); }
Localización de fondoReceptor
public class BackgroundLocationReceiver extends BroadcastReceiver { private static final String TAG = "BLocRec: "; private static final String UPLOAD_ERROR_MESSAGE = "Background Service to Upload Coordinates Failed."; private static final String UPLOAD_MESSAGE = "Coordinate Batch Pushed to Database."; public BackgroundLocationReceiver() { //Default, no-arg constructor } /** * This method handles any location updates received when the app is no longer in focus. Coordinates are * stored in the local database and uploaded once every hour. * @param context the application context * @param intent is the pending intent */ @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().matches(GPSPlotter.BACKGROUND_ACTION)) { Log.w(TAG, "BLR Received-background"); Location location = intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED); storeLocation(location, context, intent.getStringExtra(User.USER_ID)); }
EDIT El método siguiente crea una LocationRequest necesaria para invocar el método requestLocationUpdates()
/** * Private helper method used to generate a LocationRequest which will be used to handle all location updates * within the FusedLocationApi until the Interval is changed. * * @return locationRequest */ private LocationRequest buildLocationRequest() { int dateConversion = 1000; LocationRequest locationRequest = LocationRequest.create(); locationRequest.setInterval(mIntentInterval * dateConversion); locationRequest.setFastestInterval((mIntentInterval / 2) * dateConversion); locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); Log.w(TAG, "Building location request"); return locationRequest; }
EDIT Después de una larga discusión en el chat con Catherine, llegamos a la conclusión de que google play servicios de la biblioteca 7.5 tiene un error que no procesa el Parcelable Extra Ubicación pasó de FusedLocationProviderAPI cuando otros extras se ponen en el intento. Sin embargo, 7.0 proporciona esta capacidad. Ella dijo que presentará un error y veremos cuánto tarda el equipo de Android en resolver
- Error: No se pueden cambiar las dependencias de configuración ': app: _debugAnnotationProcessor' una vez que se ha resuelto
- Disposición de Android: Envuelva dos vistas de texto