Mantenga el servicio de ubicación activo cuando la aplicación esté cerrada.

Tengo un servicio que envía una notificación cuando el usuario cambia su ubicación. Este servicio funciona correctamente, pero el problema surge cuando el usuario cierra la aplicación cuando el servicio se cierra.

¿Cómo puedo hacer que el servicio siga vivo aunque la aplicación esté cerrada?

Mi servicio es:

public class LocationService extends Service implements LocationListener { public final static int MINUTE = 1000 * 60; boolean isGPSEnabled = false; boolean isNetworkEnabled = false; boolean canGetLocation = false; Location location; // location double latitude = 0; // latitude double longitude = 0; // longitude String provider; // The minimum distance to change Updates in meters private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // The minimum time between updates in milliseconds private static final long MIN_TIME_BW_UPDATES = 1 * MINUTE; // Declaring a Location Manager protected LocationManager locationManager; // Binder given to clients private final IBinder mBinder = new LocalBinder(); /** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ public class LocalBinder extends Binder { public LocationService getService() { // Return this instance of LocalService so clients can call public // methods return LocationService.this; } } @Override public IBinder onBind(Intent intent) { return mBinder; } public Location getLocation() { try { locationManager = (LocationManager) getBaseContext().getSystemService(LOCATION_SERVICE); // getting GPS status isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); // getting network status isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); if (!isGPSEnabled && !isNetworkEnabled) { // no network provider is enabled. DEFAULT COORDINATES } else { this.canGetLocation = true; if (isNetworkEnabled) { locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this); Log.d("Network", "Network Enabled"); if (locationManager != null) { location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); if (location != null) { latitude = location.getLatitude(); longitude = location.getLongitude(); } } } // if GPS Enabled get lat/long using GPS Services if (isGPSEnabled) { if (location == null) { locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this); Log.d("GPS", "GPS Enabled"); if (locationManager != null) { location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); if (location != null) { latitude = location.getLatitude(); longitude = location.getLongitude(); } } } } } } catch (Exception e) { e.printStackTrace(); } Log.i("LOCATION", "Latitude: " + latitude + "- Longitude: " + longitude); return location; } @Override public void onLocationChanged(Location arg0) { NotificationManager mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE); Intent intent = null; intent = new Intent(this, CompleteSurveyActivity.class); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this).setSmallIcon(R.drawable.ic_launcher).setAutoCancel(true) .setContentIntent(contentIntent).setContentTitle(this.getString(R.string.app_name)).setContentText("text"); // mBuilder.setContentIntent(contentIntent); mNotificationManager.notify((int) System.currentTimeMillis() % Integer.MAX_VALUE, mBuilder.build()); double longitude = location.getLongitude(); double latitude = location.getLatitude(); Log.i("LOCATION", "Latitude: " + latitude + "- Longitude: " + longitude); } @Override public void onProviderDisabled(String arg0) { } @Override public void onProviderEnabled(String arg0) { } @Override public void onStatusChanged(String arg0, int arg1, Bundle arg2) { } } 

Llamé desde aquí:

 public class MyActivity extends Activity { LocationService mService; boolean mBound = false; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get // LocalService instance LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } @Override public void onServiceDisconnected(ComponentName arg0) { mBound = false; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.my_activity); exampleButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { initService(); } }); } public void initService() { if (mBound) mService.getLocation(); } @Override protected void onStart() { super.onStart(); // Bind to LocalService Intent intent = new Intent(this, LocationService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // Unbind from the service if (mBound) { unbindService(mConnection); mBound = false; } } } 

Manifest.xml

  <service android:name=".LocationService" android:enabled="true"></service> 

En contraposición a lo que dijo @ sven-menschner, creo que un Service no vinculado es exactamente lo que necesita, ya que los servicios vinculados están sujetos a los mecanismos de vinculación / desvinculación que mataría a su servicio. Eso es lo que haría:

En su archivo Manifest, defina su servicio:

 <service android:name=".YourService" android:enabled="true" android:exported="true" android:description="@string/my_service_desc" android:label="@string/my_infinite_service"> <intent-filter> <action android:name="com.yourproject.name.LONGRUNSERVICE" /> </intent-filter> </service> 

Nota : Hay una lista de acciones ya implementadas, pero puede definir sus propias acciones para la intención de iniciar el servicio. Simplemente cree una clase singleton y defina las cadenas asignándoles una String que debe ser única. El conjunto "enabled" a true es sólo para instanciar el servicio, y exportado a true es justo en el caso de que necesite otras aplicaciones enviando intenciones a su Service . Si no es así, puede configurar el último como falso.

El siguiente paso sería iniciar el servicio desde su actividad. Eso se puede hacer fácilmente por:

 public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent servIntent = new Intent("com.yourproject.name.LONGRUNSERVICE"); startService(servIntent); ... } } 

El paso final es definir las inicializaciones del Service . Vigile el método onBind() . Dado que no desea que se limite, simplemente devuelva null . Sería algo así:

 public class MyService extends Service { @Override public IBinder onBind(Intent intent) { // This won't be a bound service, so simply return null return null; } @Override public void onCreate() { // This will be called when your Service is created for the first time // Just do any operations you need in this method. } @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } } 

Ahora su servicio se ejecutará incluso si cierra su Activity principal. Sólo queda un paso: Para ayudar a que su Service no esté terminado, ejecútelo como un servicio de primer plano (haga eso dentro de su servicio). Esto básicamente creará un icono de notificación en la barra de estado. Esto no significa que su actividad principal se está ejecutando también (es por eso que no desea un servicio vinculado), ya que las actividades y los servicios tienen diferentes ciclos de vida. Con el fin de ayudar a que el servicio de ejecutar durante tanto tiempo, tratar de mantener su montón lo más bajo posible para que evite el Android por lo que matarlo.

Una aclaración adicional: No puede probar si el servicio sigue ejecutando la matanza del DVM. Si matas al DVM, matarás todo, así también el Servicio.

Existen dos tipos de Servicios de Android: iniciados y enlazados. Usted está buscando el último. La documentación muestra cómo usarlo, a continuación hay un diagrama de ciclo de vida agradable.

En lugar de iniciar y enlazar el servicio en un paso con bindService() debe llamar a startService() . A continuación, se ejecuta hasta que lo detenga, incluso si la aplicación está cerrada. Pero no olvide detener el servicio en el momento correcto para evitar problemas de memoria, etc.

HTH

  • Cómo obtener el nombre de la ciudad por latitud y longitud en android?
  • Problemas de permiso para la ubicación en android Marshmallow applicaton
  • Dar localización falsa al emulador de Genymotion
  • Alternativa a FusedLocationProviderApi
  • Comprobación del estado del GPS con Google Play Services
  • Obtener la ubicación actual rápida y una vez en android
  • Android: compruebe si los servicios de ubicación están habilitados utilizando el proveedor de ubicación fusionado
  • GetTriggeringGeofences y getGeofenceTransition de LocationServices
  • ¿Cómo obtener la ubicación actual de este código de mapa? También intento recibir datos del vehículo del servidor cuando estoy abierto el mapa
  • Cómo mostrar el diálogo de configuración de ubicación en android?
  • Número GPS de satélites y filtrado de ubicaciones
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.