J'ai un IntentService qui est démarré à partir d'une activité et je voudrais pouvoir arrêter le service immédiatement de l'activité avec un bouton "Annuler" dans l'activité. Dès que ce bouton "Annuler" est enfoncé, je veux que le service arrête d'exécuter des lignes de code.
J'ai trouvé un certain nombre de questions similaires à cela (ie ici , ici , ici , ici ), mais pas de bonnes réponses. Activity.stopService()
et Service.stopSelf()
exécutez immédiatement la méthode Service.onDestroy()
mais laissez ensuite le code dans onHandleIntent()
terminer complètement avant de détruire le service.
Puisqu'il n'y a apparemment aucun moyen garanti de terminer immédiatement le thread du service, 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 fonction onDestroy()
méthode, puis avoir à peu près toutes les lignes du code dans onHandleIntent()
enveloppé dans sa propre clause "if" en regardant cette variable. C'est une terrible façon d'écrire du code.
Quelqu'un connaît-il une meilleure façon de procéder dans un IntentService?
Arrêter un thread ou un processus immédiatement est souvent une chose sale. Cependant, cela devrait aller si votre service est apatride.
Déclarez le service en tant que processus distinct dans le manifeste:
<service
Android:process=":service"
...
Et quand vous voulez arrêter son exécution, tuez simplement ce processus:
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<RunningAppProcessInfo> runningAppProcesses = am.getRunningAppProcesses();
Iterator<RunningAppProcessInfo> iter = runningAppProcesses.iterator();
while(iter.hasNext()){
RunningAppProcessInfo next = iter.next();
String pricessName = getPackageName() + ":service";
if(next.processName.equals(pricessName)){
Process.killProcess(next.pid);
break;
}
}
Voici l'astuce, utilisez une variable statique volatile et vérifiez l'état de continuer dans certaines lignes de votre service pour que le service continue soit 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 cela pour arrêter votre service,
MyService.shouldContinue = false;
J'ai utilisé un BroadcastReceiver dans le service qui met simplement un booléen d'arrêt à vrai. Exemple:
private boolean stop=false;
public class StopReceiver extends BroadcastReceiver {
public static final String 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);
Pour arrêter le service.
PD: J'utilise un booléen car dans mon cas, j'arrête le service dans une boucle mais vous pouvez probablement appeler unregisterReceiver et stopSelf dans onReceive.
PD2: N'oubliez pas d'appeler unregisterReceiver si le service se termine, il fonctionne normalement ou vous obtiendrez une erreur IntentReceiver fuite.
Dans le cas de IntentService il n'arrête pas ou prend toute autre demande via une action d'intention jusqu'à ce que sa méthode onHandleIntent
termine la demande 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 sera terminée.
De même, stopService(intent);
ou stopSelf();
ne fonctionne pas tant que la méthode onHandleIntent()
n'a pas terminé sa tâche.
Donc, je pense qu'ici, la meilleure solution consiste à utiliser normalement Service
ici.
J'espère que cela aidera!
Si vous utilisez un IntentService
, je pense que vous êtes bloqué en train de faire quelque chose comme vous le décrivez, où le code onHandleIntent()
doit interroger son signal "stop".
Si votre tâche d'arrière-plan est potentiellement longue, et si vous devez être en mesure de l'arrêter, je pense que vous feriez mieux d'utiliser plutôt un Service
simple. À un niveau élevé, écrivez votre service à:
AsyncTask.cancel(true)
, ou demandez à onDestroy () d'invoquer AsyncTask.cancel(true)
.En échange de la possibilité d'annuler les travaux en arrière-plan, le Service assume les responsabilités suivantes:
doInBackground()
devra gérer avec élégance InterruptedException et/ou vérifier périodiquement Thread.interrupted () et retourner "tôt".stopSelf()
est appelée (peut-être dans AsyncTask onPostExecute/onCancelled).@Override
protected void onHandleIntent(Intent intent) {
String action = intent.getAction();
if (action.equals(Action_CANCEL)) {
stopSelf();
} else if (action.equals(Action_START)) {
//handle
}
}
Esperons que ça marche.
Comme @budius l'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 Intent
gestion, avant d'effectuer la tâche importante de validation/envoi des 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 fera sa tâche de traitement de ce Intent
. Voilà comment il était censé être utilisé, parce que je ne vois pas comment vous pourriez le résoudre autrement si vous regardez le code principal.