J'ai étudié ce problème depuis des mois maintenant, est venu avec de nouvelles solutions, dont je ne suis pas heureux, car ils sont tous les massifs hacks. Je ne peux toujours pas croire qu'une classe que l'imparfait dans la conception qu'il a faites dans le cadre, et personne n'en parle, donc je suppose que je doit manquer quelque chose.
Le problème, c'est avec AsyncTask
. Selon la documentation, il
"permet de faire de l'arrière-plan opérations et publier les résultats sur le Thread de l'INTERFACE utilisateur sans avoir à manipuler les threads et/ou des gestionnaires."
L'exemple continue ensuite à montrer comment certaines exemplaire showDialog()
méthode est appelée en onPostExecute()
. Ceci, cependant, semble entièrement artificiel pour moi, parce que montrant une boîte de dialogue a toujours besoin d'une référence à un valide Context
, et une AsyncTask ne doit jamais tenir une forte référence à un objet de contexte.
La raison en est évidente: si l'activité est détruite, ce qui a déclenché la tâche? Cela peut se produire tout le temps, par exemple parce que vous avez retourné l'écran. Si la tâche de tenir une référence au contexte qui l'a créé, vous n'êtes pas seul tenant à un banal objet de contexte (la fenêtre ont été détruits, et toute interaction de l'INTERFACE utilisateur échoue avec une exception!), vous même, vous risquez de créer une fuite de mémoire.
Sauf si ma logique est erronée, ici, cela se traduit par: onPostExecute()
est tout à fait inutile, car à quoi bon, pour cette méthode à exécuter sur le thread de l'INTERFACE utilisateur si vous n'avez pas accès à n'importe quel contexte? Vous ne pouvez pas faire quelque chose de significatif ici.
Une solution de contournement serait de ne pas passer contexte des instances d'une AsyncTask, mais un Handler
de l'instance. Qui fonctionne: depuis un Gestionnaire vaguement lie le contexte et la tâche, vous pouvez échanger des messages entre eux sans risquer une fuite (à droite?). Mais cela signifierait que la prémisse de l'AsyncTask, à savoir que vous n'avez pas besoin de s'embêter avec des gestionnaires, est faux. Il semble aussi que d'abuser de Gestionnaire, puisque vous êtes l'envoi et la réception de messages sur le même thread (vous en créer un sur le thread d'INTERFACE utilisateur et de les envoyer à travers elle dans onPostExecute (), qui est également exécuté sur le thread d'INTERFACE utilisateur).
Pour couronner le tout, même avec cette solution de contournement, vous avez encore le problème que lorsque le contexte est détruit, vous avez pas de dossier de toutes les tâches qu'il a tiré. Cela signifie que vous avez à re-démarrer des tâches lors de la re-création du contexte, par exemple, après une orientation de l'écran change. C'est lent et inutile.
Ma solution à ce (tel que mis en œuvre dans le Droid-Fu de la bibliothèque) est de maintenir une cartographie de l' WeakReference
s à partir de noms de composants à leurs instances sur l'unique objet de l'application. Chaque fois qu'une AsyncTask est commencé, il enregistre le contexte de l'appel de cette carte, et sur chaque rappel, il va chercher le contexte actuel de l'instance à partir de cette cartographie. Cela garantit que vous ne serez jamais faire référence à un rassis instance de contexte et vous avez toujours accès à un contexte valide dans les rappels de sorte que vous pouvez ne significatif de l'INTERFACE utilisateur d'y travailler. Il n'y a pas de fuite, parce que les références sont faibles et sont effacées lorsque aucune instance d'un composant donné n'existe plus.
Pourtant, c'est une solution plus complexe et nécessite à la sous-classe des de la Droid-Fu de la bibliothèque de classes, ce qui en fait un assez intrusif approche.
Maintenant, je veux simplement savoir: Suis-je tout simplement massivement manque quelque chose ou est AsyncTask vraiment totalement erronée? Comment sont vos expériences de travail avec elle? Comment avez-vous résoudre ces problème?
Merci pour vos commentaires.