Citant la documentation pour AsyncTask trouvée ici , il est dit:
AsyncTasks devrait idéalement être utilisé pour des opérations courtes (quelques secondes au maximum). Executor, ThreadPoolExecutor et FutureTask.
Maintenant ma question se pose: pourquoi? La doInBackground()
fonction s'exécute sur le thread de l'interface utilisateur, alors quel mal y a-t-il à avoir une opération de longue durée ici?
android
android-asynctask
user1730789
la source
la source
doInBackground
gèle l'écran si une barre de progression n'est pas utilisée.Réponses:
C'est une très bonne question, il faut du temps en tant que programmeur Android pour bien comprendre le problème. En effet, AsyncTask a deux problèmes principaux qui sont liés:
Dans l' application RoboSpice Motivations ( disponible sur Google Play ), nous répondons à cette question en détail. Il vous donnera une vue approfondie des AsyncTasks, des chargeurs, de leurs fonctionnalités et inconvénients et vous présentera également une solution alternative pour les requêtes réseau: RoboSpice. Les requêtes réseau sont une exigence courante dans Android et sont par nature des opérations de longue durée. Voici un extrait de l'application:
Le cycle de vie AsyncTask et Activity
AsyncTasks ne suit pas le cycle de vie des instances Activity. Si vous démarrez une AsyncTask à l'intérieur d'une activité et que vous faites pivoter l'appareil, l'activité sera détruite et une nouvelle instance sera créée. Mais l'AsyncTask ne mourra pas. Il continuera à vivre jusqu'à ce qu'il soit terminé.
Et une fois terminé, AsyncTask ne mettra pas à jour l'interface utilisateur de la nouvelle activité. En effet, il met à jour l'ancienne instance de l'activité qui n'est plus affichée. Cela peut conduire à une exception de type java.lang.IllegalArgumentException: vue non attachée au gestionnaire de fenêtres si vous utilisez, par exemple, findViewById pour récupérer une vue à l'intérieur de l'activité.
Problème de fuite de mémoire
Il est très pratique de créer des AsyncTasks en tant que classes internes de vos activités. 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.
Néanmoins, cela signifie que la classe interne contiendra une référence invisible sur son instance de classe externe: l'activité.
Sur le long terme, cela produit une fuite de mémoire: si l'AsyncTask dure longtemps, elle maintient l'activité "vivante" alors qu'Android voudrait s'en débarrasser car elle ne peut plus être affichée. L'activité ne peut pas être récupérée et c'est un mécanisme central pour Android pour préserver les ressources sur l'appareil.
C'est vraiment une très très mauvaise idée d'utiliser AsyncTasks pour des opérations de longue durée. Néanmoins, ils conviennent pour ceux qui sont de courte durée, tels que la mise à jour d'une vue après 1 ou 2 secondes.
Je vous encourage à télécharger l' application RoboSpice Motivations , elle explique vraiment cela en profondeur et fournit des exemples et des démonstrations des différentes façons d'effectuer certaines opérations en arrière-plan.
la source
Car
AsyncTask
, par défaut, utilise un pool de threads que vous n'avez pas créé . Ne jamais lier des ressources d'un pool que vous n'avez pas créé, car vous ne savez pas quelles sont les exigences de ce pool. Et n'attachez jamais de ressources d'un pool que vous n'avez pas créé si la documentation de ce pool vous dit de ne pas le faire, comme c'est le cas ici.En particulier, à partir d'Android 3.2, le pool de threads utilisé par
AsyncTask
défaut (pour les applications avec une valeurandroid:targetSdkVersion
de 13 ou plus) ne contient qu'un seul thread - si vous liez ce thread indéfiniment, aucune de vos autres tâches ne s'exécutera.la source
Service
, utilisez simplement aThread
ou aThreadPoolExecutor
.TimerTask
provient de Java standard, pas d'Android.TimerTask
a été largement abandonné au profit deScheduledExecutorService
(qui, malgré son nom, fait partie de Java standard). Ni l'un ni l'autre ne sont liés à Android, et vous avez donc toujours besoin d'un service si vous vous attendez à ce que ces choses s'exécutent en arrière-plan. Et, vous devriez vraiment envisagerAlarmManager
, à partir d'Android, de sorte que vous n'avez pas besoin d'un service qui traîne juste en regardant le tic-tac de l'horloge.Les tâches Aysnc sont des threads spécialisés qui sont toujours destinés à être utilisés avec l'interface graphique de vos applications, mais tout en conservant les tâches lourdes en ressources du thread d'interface utilisateur. Ainsi, lorsque des éléments tels que la mise à jour de listes, la modification de vos vues, etc. vous obligent à effectuer des opérations de récupération ou de mise à jour, vous devez utiliser des tâches asynchrones afin de pouvoir garder ces opérations hors du thread de l'interface utilisateur, mais notez que ces opérations sont toujours connectées à l'interface utilisateur. .
Pour les tâches plus longues, qui ne nécessitent pas de mise à jour de l'interface utilisateur, vous pouvez utiliser des services à la place, car ils peuvent vivre même sans interface utilisateur.
Donc, pour les tâches courtes, utilisez des tâches asynchrones car elles peuvent être tuées par le système d'exploitation après la mort de votre activité de frai (généralement ne mourra pas en cours d'opération mais terminera sa tâche). Et pour les tâches longues et répétitives, utilisez plutôt des services.
pour plus d'informations, voir les fils:
AsyncTask pendant plus de quelques secondes?
et
AsyncTask ne s'arrête pas même lorsque l'activité est détruite
la source
Le problème avec AsyncTask est que s'il est défini comme une classe interne non statique de l'activité, il aura une référence à l'activité. Dans le scénario où l'activité du conteneur de la tâche asynchrone se termine, mais le travail d'arrière-plan dans AsyncTask se poursuit, l'objet activité ne sera pas récupéré car il y a une référence à celui-ci, cela provoque la fuite de mémoire.
La solution pour résoudre ce problème est de définir la tâche asynchrone en tant que classe interne statique d'activité et à utiliser une référence faible au contexte.
Mais toujours, c'est une bonne idée de l'utiliser pour des tâches d'arrière-plan simples et rapides. Pour développer une application avec un code propre, il est préférable d'utiliser RxJava pour exécuter des tâches d'arrière-plan complexes et mettre à jour l'interface utilisateur avec les résultats.
la source