Cómo ejecutar siempre un servicio en segundo plano?

Estoy en el proceso de crear una aplicación que es similar a la aplicación de SMS integrada.

Lo que necesito:

  • un servicio que siempre se ejecuta en segundo plano
  • cada 5 min. el servicio verifica la ubicación actual del dispositivo y llama a un servicio web
  • si se cumplen ciertos criterios, el servicio debe generar una notificación (al igual que la aplicación de SMS)
  • cuando se hace clic en la notificación, se lleva al usuario a la aplicación (al igual que la aplicación de SMS)
  • cuando se instala la aplicación, se debe iniciar el servicio
  • cuando se reinicia el dispositivo, se debe iniciar el servicio

Lo que he intentado:
– ejecutando un servicio regular que funcionó bien hasta que Android mata el servicio
– usando el AlarmManager para hacer los 5 min. llamada de intervalo a un servicio. Pero no pude hacer que esto funcione.

un servicio que siempre se ejecuta en segundo plano

Esto no es posible en ningún sentido real del término, como has descubierto. También es un mal diseño .

cada 5 min. el servicio verifica la ubicación actual del dispositivo y llama a un servicio web

Use AlarmManager .

usando el AlarmManager haga los 5 min. llamada de intervalo a un servicio. Pero no pude hacer que esto funcione.

Aquí hay un proyecto de muestra que muestra cómo usar uno, junto con el uso de WakefulIntentService para que se mantenga despierto mientras intenta hacer todo el servicio web.

Si continúa teniendo problemas, abra una nueva pregunta sobre las cosas específicas que se encuentra con AlarmManager que le AlarmManager dolor.

Una de mis aplicaciones hace algo muy similar. Para reactivar el servicio después de un período determinado, recomiendo postDelayed()

Tener un campo de controlador:

 private final Handler handler = new Handler(); 

y un refrescante Runnable

 private final Runnable refresher = new Runnable() { public void run() { // some action } }; 

Puede disparar sus Notificaciones en el ejecutable.

En la construcción del servicio, y después de cada ejecución, comienza así:

 handler.postDelayed(refresher, /* some delay in ms*/); 

En onDestroy() eliminar la publicación

 handler.removeCallbacks(refresher); 

Para iniciar el servicio en el arranque, necesita un autoarranque. Esto va en tu manifiesto

      

y ServiceAutoStarter ve así:

 public class ServiceAutoStarter extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { context.startService(new Intent(context, UpdateService.class)); } } 

Detener el sistema operativo de matar el servicio es complicado. Además, su aplicación puede tener una RuntimeException y fallar, o su lógica puede paralizarse.

En mi caso, pareció ayudar a actualizar siempre el servicio en pantalla con un BroadcastReceiver . Entonces, si la cadena de actualizaciones se detiene, resucitará cuando el usuario use su teléfono.

En el servicio:

 private BroadcastReceiver screenOnReceiver; 

En su servicio onCreate()

 screenOnReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // Some action } }; registerReceiver(screenOnReceiver, new IntentFilter(Intent.ACTION_SCREEN_ON)); 

A continuación, onDestroy() el registro de su servicio en onDestroy() con

 unregisterReceiver(screenOnReceiver); 

Puede hacerlo mediante una implementación simple:

 public class LocationTrace extends Service implements LocationListener{ // The minimum distance to change Updates in meters private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters private static final int TWO_MINUTES = 100 * 10; // The minimum time between updates in milliseconds private static final long MIN_TIME_BW_UPDATES = 1000 * 10; // 30 seconds private Context context; double latitude; double longitude; Location location = null; boolean isGPSEnabled = false; boolean isNetworkEnabled = false; protected LocationManager locationManager; @Override public int onStartCommand(Intent intent, int flags, int startId) { this.context = this; get_current_location(); // Toast.makeText(context, "Lat"+latitude+"long"+longitude,Toast.LENGTH_SHORT).show(); return START_STICKY; } @Override public void onLocationChanged(Location location) { if((location != null) && (location.getLatitude() != 0) && (location.getLongitude() != 0)){ latitude = location.getLatitude(); longitude = location.getLongitude(); if (!Utils.getuserid(context).equalsIgnoreCase("")) { Double[] arr = { location.getLatitude(), location.getLongitude() }; // DO ASYNCTASK } } } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } /* * Get Current Location */ public Location get_current_location(){ locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); if(!isGPSEnabled && !isNetworkEnabled){ }else{ if (isGPSEnabled) { if (location == null) { locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this); if (locationManager != null) { location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); if (location != null) { latitude = location.getLatitude(); longitude = location.getLongitude(); // Toast.makeText(context, "Latgps"+latitude+"long"+longitude,Toast.LENGTH_SHORT).show(); } } } } if (isNetworkEnabled) { locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this); if (locationManager != null) { if (location != null) { latitude = location.getLatitude(); longitude = location.getLongitude(); // Toast.makeText(context, "Latgps1"+latitude+"long"+longitude,Toast.LENGTH_SHORT).show(); } } } } return location; } public double getLatitude() { if(location != null){ latitude = location.getLatitude(); } return latitude; } public double getLongitude() { if(location != null){ longitude = location.getLongitude(); } return longitude; } @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { if(locationManager != null){ locationManager.removeUpdates(this); } super.onDestroy(); } } 

Puede comenzar el servicio de esta manera:

 /*--Start Service--*/ startService(new Intent(Splash.this, LocationTrace.class)); 

En manifiesto:

        

con estos tres pasos, puede reactivar cada 5 minutos la mayoría de los dispositivos Android:

1. configure su AlarmManager alternativo para diferentes API:

 AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE); Intent i = new Intent(getApplicationContext(), OwnReceiver.class); PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), 0, i, 0); if (Build.VERSION.SDK_INT >= 23) { am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi); } else if (Build.VERSION.SDK_INT >= 19) { am.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi); } else { am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi); } 

2. construye tu propio BroadcastReceiver estático:

 public static class OwnReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //do all of your jobs here AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent i = new Intent(context, OwnReceiver.class); PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0); if (Build.VERSION.SDK_INT >= 23) { am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi); } else if (Build.VERSION.SDK_INT >= 19) { am.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi); } else { am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi); } } } 

3. agregue a AndroidManifest.xml :