Comment forcer un IntentService à s’arrêter immédiatement avec un bouton Annuler d’une activité?

J’ai un IntentService qui est lancé à partir d’une activité et je voudrais pouvoir arrêter le service immédiatement à partir de l’activité avec un bouton “annuler” dans l’activité. Dès que ce bouton “annuler” est pressé, je veux que le service arrête d’exécuter des lignes de code.

J’ai trouvé un certain nombre de questions similaires (c.-à-d. Ici , ici , ici , ici ), mais pas de bonnes réponses. Activity.stopService() et Service.stopSelf() exécutent la méthode Service.onDestroy() immédiatement, puis laissez le code dans onHandleIntent() terminer complètement avant de détruire le service.

Comme il n’ya apparemment pas de moyen garanti pour terminer le thread du service immédiatement, la seule solution recommandée que je peux trouver ( ici ) est d’avoir une variable membre booléenne dans le service qui peut être commutée dans la méthode onDestroy() , chaque ligne du code dans onHandleIntent() enveloppée dans sa propre clause “if” regardant cette variable. C’est une façon terrible d’écrire du code.

Est-ce que quelqu’un connaît une meilleure façon de faire cela dans IntentService?

Arrêter immédiatement un thread ou un processus est souvent une mauvaise chose. Cependant, cela devrait aller si votre service est apasortingde.

Déclarez le service comme un processus distinct dans le manifeste:

  

Et quand vous voulez arrêter son exécution, tuez simplement ce processus:

 ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE); List runningAppProcesses = am.getRunningAppProcesses(); Iterator iter = runningAppProcesses.iterator(); while(iter.hasNext()){ RunningAppProcessInfo next = iter.next(); Ssortingng pricessName = getPackageName() + ":service"; if(next.processName.equals(pricessName)){ Process.killProcess(next.pid); break; } } 

Voici le truc, utilisez une variable statique volatile et vérifiez que la condition continue dans certaines des lignes de votre service que le service continu doit être vérifié:

 class MyService extends IntentService { public static volatile boolean shouldContinue = true; public MyService() { super("My Service"); } @Override protected void onHandleIntent(Intent intent) { doStuff(); } private void doStuff() { // do something // check the condition if (shouldContinue == false) { stopSelf(); return; } // continue doing something // check the condition if (shouldContinue == false) { stopSelf(); return; } // put those checks wherever you need } } 

et dans votre activité faites ceci pour arrêter votre service,

  MyService.shouldContinue = false; 

J’ai utilisé un BroadcastReceiver dans le service qui met simplement un stop booléen à true. Exemple:

 private boolean stop=false; public class StopReceiver extends BroadcastReceiver { public static final Ssortingng ACTION_STOP = "stop"; @Override public void onReceive(Context context, Intent intent) { stop = true; } } @Override protected void onHandleIntent(Intent intent) { IntentFilter filter = new IntentFilter(StopReceiver.ACTION_STOP); filter.addCategory(Intent.CATEGORY_DEFAULT); StopReceiver receiver = new StopReceiver(); registerReceiver(receiver, filter); // Do stuff .... //In the work you are doing if(stop==true){ unregisterReceiver(receiver); stopSelf(); } } 

Ensuite, à partir de l’appel d’activité:

 //STOP SERVICE Intent sIntent = new Intent(); sIntent.setAction(StopReceiver.ACTION_STOP); sendBroadcast(sIntent); 

Arrêter le service

PD: J’utilise un booléen parce que dans mon cas, j’arrête le service en boucle mais vous pouvez probablement appeler unregisterReceiver et stopSelf dans onReceive.

PD2: N’oubliez pas d’appeler unregisterReceiver si le service se termine normalement ou si vous obtenez une erreur de IntentReceiver.

Dans le cas d’ IntentService, il ne s’arrête pas ou prend toute autre requête via une action intentionnelle jusqu’à ce que sa méthode onHandleIntent termine la requête précédente.

Si nous essayons de redémarrer IntentService avec une autre action, onHandleIntent sera appelé uniquement lorsque l’intention / la tâche précédente est terminée.

Également stopService(intent); ou stopSelf(); ne fonctionne pas tant que la méthode onHandleIntent() n’a pas terminé sa tâche.

Je pense donc que la meilleure solution consiste à utiliser le Service normal ici.

J’espère que cela aidera!

Si vous utilisez un IntentService , alors je pense que vous êtes coincé à faire quelque chose comme vous décrivez, où le code onHandleIntent() doit interroger son signal “stop”.

Si votre tâche en arrière-plan est potentiellement longue et que vous devez être capable de l’arrêter, je pense que vous devriez plutôt utiliser un Service ordinaire. Au plus haut niveau, écrivez votre service à:

  • Exposez une intention “start” pour démarrer une tâche AsyncTask pour effectuer votre travail en arrière-plan, en enregistrant une référence à cette AsyncTask nouvellement créée.
  • Exposer une intention “annuler” pour invoquer AsyncTask.cancel(true) ou demander à onDestroy () d’appeler AsyncTask.cancel(true) .
  • L’activité peut alors soit envoyer l’intention “annuler” ou appeler simplement stopService ().

En échange de la possibilité d’annuler le travail de fond, le Service assume les responsabilités suivantes:

  • AsyncTask doInBackground() devra gérer doInBackground() InterruptedException et / ou vérifier périodiquement l’existence de Thread.interrupted () et renvoyer «tôt».
  • Le service devra s’assurer que stopSelf() est appelé (peut-être dans AsyncTask onPostExecute / onCancelled).
 @Override protected void onHandleIntent(Intent intent) { Ssortingng action = intent.getAction(); if (action.equals(Action_CANCEL)) { stopSelf(); } else if (action.equals(Action_START)) { //handle } } 

Esperons que ça marche.

Comme @budius a déjà mentionné dans son commentaire, vous devez définir un booléen sur le Service lorsque vous cliquez sur ce bouton:

 // your Activity.java public boolean onClick() { //... mService.performTasks = false; mService.stopSelf(); } 

Et dans votre gestion des Intent , avant de faire la tâche importante de valider / envoyer les informations d’intention, utilisez simplement ce booléen:

 // your Service.java public boolean performTasks = true; protected void onHandleIntent(Intent intent) { Bundle intentInfo = intent.getBundle(); if (this.performTasks) { // Then handle the intent... } } 

Sinon, le service effectuera sa tâche de traitement de cette Intent . C’est comme ça que c’était censé être utilisé, parce que je ne vois pas comment vous pourriez le résoudre autrement si vous regardez le code de base.

Voici un exemple de code pour démarrer / arrêter le service

Commencer,

 Intent GPSService = new Intent(context, TrackGPS.class); context.startService(GPSService); 

Arrêter,

context.stopService(GPSService);

 context.stopService(GPSService);