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 .

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?

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 un PendingIntent 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

  • Servicios de Android Play FusedLocatioAPI getLastLocation se bloquea con SecurityException
  • Faltan los servicios de Google Play en el emulador de Android 2.2 mientras usas Google Maps API v2
  • Varios Proguard nuevas publican los servicios de Google Play v10.2.6 a v11.0.0 en un proyecto Multidex
  • Do Geofences permanece activo en android después de reiniciar el dispositivo
  • Causa de inicio de sesión de Google: Causado por: java.util.ConcurrentModificationException
  • ¿De dónde provienen las sugerencias de inicio de sesión de Smart Lock for Passwords y cómo personalizarlas?
  • ¿Cómo puedo hacer coincidir una revisión de Servicios de Google Play con una versión de instalación?
  • Búsqueda de Android PlacePicker
  • Google AppInvites rompe la construcción
  • Appcompat-v7: 21.0.0 no funciona con el servicio de Google Play 6.1+
  • Hacer que Android Geofences permanezca activo hasta que se haya eliminado / caducado o solo hasta que se inicie mi PendingIntent
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.