Comment toujours exécuter un service en arrière-plan?

Je suis en train de créer une application similaire à l’application SMS intégrée.

Ce dont j’ai besoin:

  • un service qui tourne toujours en arrière-plan
  • toutes les 5 min. le service vérifie l’emplacement actuel de l’appareil et appelle un service Web
  • Si certains critères sont remplis, le service devrait générer une notification (tout comme l’application SMS)
  • lorsque la notification est cliquée, l’utilisateur est amené à l’application (tout comme l’application SMS)
  • lorsque l’application est installée, le service doit être démarré
  • au redémarrage de l’appareil, le service doit être démarré

Ce que j’ai essayé:
– exécuter un service régulier qui fonctionnait très bien jusqu’à ce que Android tue le service
– utiliser le AlarmManager pour faire les 5 min. appel à intervalle à un service. Mais je n’ai pas pu faire ce travail.

    un service qui tourne toujours en arrière-plan

    Ce n’est pas possible dans le vrai sens du terme, comme vous l’avez découvert. C’est aussi un mauvais design .

    toutes les 5 min. le service vérifie l’emplacement actuel de l’appareil et appelle un service Web

    Utilisez AlarmManager .

    en utilisant le AlarmManager le make 5 min. appel à intervalle à un service. Mais je n’ai pas pu faire ce travail.

    Voici un exemple de projet montrant comment en utiliser un, ainsi que l’utilisation de WakefulIntentService pour que vous WakefulIntentService éveillé en essayant de faire tout le service Web.

    Si vous rencontrez toujours des problèmes, ouvrez une nouvelle question sur les problèmes spécifiques que vous rencontrez avec AlarmManager qui vous posent AlarmManager .

    Une de mes applications fait quelque chose de très similaire. Pour réveiller le service après une période donnée, je recommande postDelayed()

    Avoir un champ de gestionnaire:

     private final Handler handler = new Handler(); 

    et un recyclage Runnable

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

    Vous pouvez déclencher vos notifications dans l’exécutable.

    Lors de la construction du service, et après chaque exécution, commencez comme suit:

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

    Dans onDestroy() supprimez le message

     handler.removeCallbacks(refresher); 

    Pour démarrer le service au démarrage, vous avez besoin d’un démarreur automatique. Cela va dans votre manifeste

          

    et le ServiceAutoStarter ressemble à ceci:

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

    Empêcher le système d’exploitation de tuer le service est délicat. De plus, votre application peut avoir une RuntimeException et un plantage, ou votre logique peut être bloquée.

    Dans mon cas, cela semblait aider à toujours actualiser le service à l’écran avec un BroadcastReceiver . Donc, si la chaîne de mises à jour est bloquée, elle sera ressuscitée lorsque l’utilisateur utilisera son téléphone.

    Dans le service:

     private BroadcastReceiver screenOnReceiver; 

    Dans votre service onCreate()

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

    Puis onDestroy() votre service sur onDestroy() avec

     unregisterReceiver(screenOnReceiver); 

    Vous pouvez le faire par une implémentation 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(Ssortingng provider, int status, Bundle extras) { } @Override public void onProviderEnabled(Ssortingng provider) { } @Override public void onProviderDisabled(Ssortingng 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(); } } 

    Vous pouvez commencer le service par ceci:

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

    En manifeste:

            

    Par ces trois étapes, vous pouvez réveiller toutes les 5 minutes la plupart des appareils Android:

    1. définissez votre AlarmManager alternatif pour différentes 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. construisez votre propre BroadcastReceiver statique:

     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. Ajoutez à AndroidManifest.xml :