La réponse donnée par @Romain Guy est correcte. Néanmoins, j'aimerais ajouter un complément d'information et donner un pointeur vers une ou deux bibliothèques qui peuvent être utilisées pour les AsyncTask de longue durée et encore plus pour les asynctasks orientés réseau.
Les tâches asynchrones ont été conçues pour effectuer des tâches en arrière-plan. Et oui, vous pouvez les arrêter en utilisant la fonction cancel
méthode. Lorsque vous téléchargez des documents sur l'internet, je vous conseille vivement de s'occuper de votre thread lorsqu'il est dans l'état de blocage de l'IO . Vous devez organiser votre téléchargement comme suit :
public void download() {
//get the InputStream from HttpUrlConnection or any other
//network related stuff
while( inputStream.read(buffer) != -1 && !Thread.interrupted() ) {
//copy data to your destination, a file for instance
}
//close the stream and other resources
}
L'utilisation de la Thread.interrupted
aidera votre thread à quitter correctement un état io bloquant. Votre thread sera plus réactif à l'invocation de la fonction cancel
méthode.
Défaut de conception d'AsyncTask
Mais si votre AsyncTask dure trop longtemps, vous serez confronté à deux problèmes différents :
- Les activités sont mal liées au cycle de vie de l'activité et vous n'obtiendrez pas le résultat de votre AsyncTask si votre activité meurt. En effet, si, vous pouvez le faire mais ce sera de manière approximative.
- Les AsyncTask ne sont pas très bien documentés. Une mise en œuvre et une utilisation naïves, bien qu'intuitives, d'une tâche asynchrone peuvent rapidement entraîner des fuites de mémoire.
RoboSpice la bibliothèque que j'aimerais présenter, utilise un service d'arrière-plan pour exécuter ce type de requêtes. Il a été conçu pour les requêtes réseau. Elle offre des fonctionnalités supplémentaires telles que la mise en cache automatique des résultats des requêtes.
Voici la raison pour laquelle les AsyncTasks ne sont pas adaptées aux tâches de longue durée. Le raisonnement suivant est une adaptation d'extraits de Motivations de RoboSpice : l'application qui explique pourquoi l'utilisation de RoboSpice répond à un besoin sur la plateforme Android.
Le cycle de vie de l'AsyncTask et de l'Activity
Les tâches asynchrones ne suivent pas le cycle de vie des instances d'activité. Si vous démarrez une AsyncTask à l'intérieur d'une Activity et que vous faites pivoter l'appareil, l'Activity sera détruite et une nouvelle instance sera créée. Mais l'AsyncTask ne mourra pas. Elle continuera à vivre jusqu'à ce qu'elle soit terminée.
Et lorsqu'elle se termine, l'AsyncTask ne met pas à jour l'interface utilisateur de la nouvelle activité. En effet, elle met à jour l'ancienne instance de l'activité qui n'est plus affichée. Cela peut conduire à une exception de type java.lang.IllegalArgumentException : View not attached to window manager si vous utilisez, par exemple, findViewById pour récupérer une vue à l'intérieur de l'Activity.
Problème de fuite de mémoire
Il est très pratique de créer des AsyncTasks en tant que classes internes de vos Activities. Comme l'AsyncTask devra manipuler les vues de l'activité lorsque la tâche est terminée ou en cours, l'utilisation d'une classe interne de l'activité semble pratique : les classes internes peuvent accéder directement à n'importe quel champ de la classe externe. Les classes internes peuvent accéder directement à n'importe quel champ de la classe externe.
Néanmoins, cela signifie que la classe interne détiendra une référence invisible sur l'instance de la classe externe : l'activité.
A long terme, cela produit une fuite de mémoire : si l'AsyncTask dure longtemps, elle maintient l'activité "en vie" alors qu'Android voudrait s'en débarrasser car elle ne peut plus être affichée. L'activité ne peut pas être ramassée et c'est un mécanisme central de la gestion de l'activité. mécanisme central d'Android pour préserver les ressources sur l'appareil.
La progression de votre tâche sera perdue
Vous pouvez utiliser des solutions de contournement pour créer une tâche asynchrone de longue durée et gérer son cycle de vie en fonction du cycle de vie de l'activité. Vous pouvez soit annuler l'AsyncTask dans la méthode onStop de votre activité ou vous pouvez laisser votre tâche asynchrone se terminer, et ne pas perdre sa progression et son le relier à l'instance suivante de votre activité .
C'est possible et nous montrons comment dans les motivations de RobopSpice, mais cela devient compliqué et le code n'est pas vraiment générique. De plus, vous perdrez toujours la progression de votre tâche si l'utilisateur quitte l'activité et revient. Le même problème se pose avec les chargeurs, bien qu'il s'agisse d'un équivalent plus simple de la solution AsyncTask avec relinking mentionnée ci-dessus.
Utilisation d'un service Android
La meilleure solution consiste à utiliser un service pour exécuter vos tâches de fond de longue durée. Et c'est exactement la solution proposée par RoboSpice. Encore une fois, cette bibliothèque est conçue pour les réseaux, mais elle pourrait être étendue à des choses qui ne sont pas liées aux réseaux. Cette bibliothèque dispose d'un un grand nombre de fonctionnalités .
Vous pouvez même vous en faire une idée en moins de 30 secondes grâce à une infographies .
C'est vraiment une très très mauvaise idée d'utiliser les AsyncTasks pour des opérations de longue durée. Néanmoins, elles conviennent parfaitement pour les opérations de courte durée, comme la mise à jour d'une vue après 1 ou 2 secondes.
Je vous encourage à télécharger le RoboSpice Motivations app Il explique vraiment tout cela en profondeur et fournit des exemples et des démonstrations des différentes façons de faire des choses liées au réseau.
Si vous cherchez une alternative à RoboSpice pour des tâches non liées au réseau (par exemple sans cache), vous pouvez également consulter les sites suivants Ruban .