Apache Adobe Flex TutorialTutoriaux Adobe Flex & AIR en Français

7mai/115

AIR Mobile – Le cycle de vie des View (destructionPolicy, viewActivate, …)

Comme on l'a vu dans le tutorial AIR Mobile précédent, on a un ViewNavigator qui gère l'instanciation et l'affichage des View:

AIR Mobile – Navigation entre les View : pushView, popView, …

Vous n'êtes donc plus maître des évènements en ce qui concerne les instanciations mais bien entendu, le SDK est accessible et extensible. Des évènements sont donc propagés pour vous permettre d'insérer votre logique métier au bon moment.

Les évènements propagés par View

Les objets de type View vont propagés 2 nouveaux types d'évènements:

  • FlexEvent.VIEW_ACTIVATE ("viewActivate") : Envoyé quand la vue est devenue la vue courante ("activeView" sur ViewNavigator)
  • FlexEvent.VIEW_DEACTIVATE ("viewDeactivate") : Envoyé quand on va remplacer cette vue par une autre.
  • FlexEvent.REMOVING ("removing") : Envoyé lorsque la vue s'apprête à être supprimée car elle on a demandé l'activation d'une autre vue. Vous pouvez appeler la méthode preventDefault() sur cet évènement pour empêcher le changement d'écran.

Attention, l'évènement VIEW_ACTIVATE n'est envoyé qu'une fois la transition terminée. Il ne faut pas confondre VIEW_ACTIVATE et CREATION_COMPLETE qui aussi propagé par une View. FlexEvent.CREATION_COMPLETE indique que les composants de la vue ont été créés et qu'ils sont accessibles. FlexEvent.VIEW_ACTIVATE signifie que l'utilisateur peut agir sur la vue (il ne peut pas agir sur une View pendant une transition.

Voici le schéma complet expliquant cette mécanique récupéré depuis les specifications Hero 4.5 :

viewLifeCycle

Politique de destruction des View

Comme on le voit dans l'enchaînement des évènements, à un moment donné, la vue A est supprimée de l'affichage. Le comportement par défaut est que lorsqu'une View est désactivée (remplacée par une autre), celle-ci est détruite automatiquement. Là encore, ce n'est pas pour le plaisir de la détruire, cela va surtout aider votre application à garder une consommation mémoire basse. En effet, avec ce système, vous n'aurez à un instant T, qu'une View en mémoire, la View courante.

Mais dans certains cas, vous ne voudrez pas que la vue soit détruite. Imaginez que dans votre application, vous ayez une vue qui ait un temps d'initialisation assez long ou que l'utilisateur puisse effectuer des actions qui ne soient pas seulement "cliquer sur un item de liste".

Voici deux exemples pour lesquels vous ne souhaitez pas détruire votre vue:

  • Vous concevez une application de dessin et votre vue principale est un "tableau blanc" sur lequel l'utilisateur peut dessiner au doigt. L'utilisateur réalise plusieurs dessins puis va sur l'écran de paramétrage pour modifier une option (une autre View). Votre View principale serait alors détruite et au retour de votre vue de paramétrage, il faudrait dessiner à nouveau tout ce que l'utilisateur était en train de faire. Même si cela est possible, cela n'est pas très pratique et va ralentir l'utilisateur dans sa navigation.
  • Un exemple auquel j'ai été confronté dans mon application, celui d'une vue longue à initialiser. Dans mon cas, c'est ma carte qui comprend de nombreux objets graphiques (tuiles images, des Shape) créés à l'avance dans un Object Pool. La navigation courante de l'utilisateur est aussi importante. Si l'utilisateur s'est déplacé sur un point précis, il voudra revenir à ce point. Même si cette position est sauvegardée, il serait trop long de recréer mon composant carte, de l'initialiser et de le replacer à chaque fois que l'utilisateur revient sur la vue de la carte.

Il y a sûrement d'autres exemples mais ceux-ci sont ceux qui me viennent directement en tête.

Si votre vue n'est pas complexe, il est conseillé de laisser AIR la détruire / créer pour éviter que l'application gonfle en mémoire. Sinon, vous pouvez utiliser le paramètre "destructionPolicy" qui est présent sur View. Si vous donnez la valeur "never"  à "destructionPolicy", votre vue ne sera pas détruite et pourra être réutiliser en cas de retour du cette vue.

"Never Say Never"

Pour reprendre l'expression de notre ami chevelu, il ne faut jamais dire jamais. En effet, même si votre vue a une "destructionPolicy" fixée à "never", dans certains cas, la vue va être recrée.

Dans mon application, par exemple, j'ai les vues suivantes:

  • Map
  • Recherche
  • Resultats
  • Fiche Info

Si l'utilisateur fait le cheminement suivant:

Map > Search > BACK (popView) > Map

Parfait, notre vue Map n'a pas été détruite et on a bien pu la récupérer. Prenons maintenant le cheminement suivant, en réalisant un "pushView" à chaque étape:

Map > Search > Result > Info Sheet > Map

Et bien dans ce cas, le ViewNavigator va créer une nouvelle vue Map. Pour résumer, lorsque vous faîtes appel à pushView, même si vous lui donnez une Class qui a déjà été instanciée auparavant, ViewNavigator va créer une nouvelle vue et peu importe la destructionPolicy de celle-ci.

Il faut noter que le cheminement suivant ne détruit pas la vue:

Map > Search > Result > Info Sheet > popView();popView();popView(); > Map

Mais ce n'est pas une vraie solution. Etant confronté directement à ce problème, j'ai du trouver une solution (merci au forum de la prerelease pour le coup de main) que je partagerai sur flex-tutorial.

Articles similaires

Commentaires (5) Trackbacks (0)
  1. Salut Fabien,

    Une question sur la destructionPlicy à "never", si on fait un "popView()" sur une vue avec "never", est-ce qu'elle est gardée encore en mémoire ou là, elle va bien être détruite ?
    Car mon application comporte plusieurs vues avec "never", et même quand je reviens sur l'écran principal, l'application 'mange' encore beaucoup de mémoire je trouve.

    Merci

  2. Salut Tristan, j'espère que tu vas bien ;)

    Comme je le dis sur la fin, le comportement de la destructionPolicy est quelque peu étrange dans certains cas. En tous cas, si tu mets la destructionPolicy à "never", quand tu fais un pop, la vue restera en mémoire mais si tu refais un push, une nouvelle vue sera créée, qui ne sera pas détruite donc il faut faire attention.

    Fabien

  3. Re,

    Oui, ça va bien, et toi aussi j'espère.
    J'avoue que c'est pas très clair leur histoire de destructionPolicy.
    Vivement ton prochain tutoriel sur la navigationStack ! :)

    Et merci pour ta réponse

  4. Salut Fabien,

    Merci pour toutes ces explications.
    Je suis débutant en Flex, donc ce qui va suivre est peut-être totalement à côté de la plaque, si c'est le cas n'hésite pas à me le dire :)

    Si j'essai de tirer tout ça au clair, en fait, passer la destructionPolicy à never ne présente d'intérêt que si cette vue est la racine de l'application. Car le fait de faire un push de la vue va créer une nouvelle instance de celle-ci, et on se retrouve donc avec un doublon de notre vue, d'où une surcharge de mémoire pour rien, ce qui me fait dire qu'il faut éviter d'arriver à cette vue par un pushView..

    A partir de là, plusieurs choses :

    - 1/ Si notre vue principale est en never, et que le seul moyen de l'afficher est de faire des popView jusqu'à revenir à son niveau, on a tout bon : on utilise bien cette instance de notre view et on n'en crée jamais de nouvelle.
    - 2/ Du coup, si on "revient" à notre vue principale par un popToFirstView, j'imagine qu'on a bon aussi, comme je le décris dans la ligne précédente (est-ce que popToFirstView recrée une nouvelle instance, ou est-ce qu'il agit comme une succession de popView ?)
    - 3/ Et pour finir je me demande donc s'il ne serait pas possible de stocker en mémoire notre vue dans une variable FlexGlobals.topLevelApplication.maVueEnNever, et de faire un pushView qui prendrait comme paramètre cette variable au lieu de prendre un type de vue et un data ?

    Je dis peut-être n'importe quoi, je n'ai pas vérifié du tout, mais dans l'idée ça me parait plutôt intéressant, et sinon je ne vois vraiment pas l'intérêt d'une destructionPolicy à never sauf si on entre dans une navigation contrainte comme je le décris dans les points 1 et 2..

    Merci encore et à bientôt,
    Fabien S

  5. Salut,
    et bien tu as tout compris ;) .
    Pour ton 3/, ce n'est pas possible. Quand on fait un pushView, on donne une Class et pas une instance. Donc tu ne pas passer un objet à ré-utiliser

    Fabien


Leave a comment

(required)

Aucun trackbacks pour l'instant