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

1nov/108

Flex et composants mobile (AIR pour Android – iOS) – L'approche Hero

La dernière release du SDK Flex, Flex 4.5 alias "Hero" comporte des composants prévus pour la mise en place d'interfaces pour mobile. Vous pourrez aller jeter un oeil sur les spécifications de ces composants sur le site qui y est consacré. Par exemple, la spécification sur les composants View et ViewNavigator:

http://opensource.adobe.com/wiki/display/flexsdk/View+and+ViewNavigator

Cela fait quelques mois que la sortie de Hero a pris du retard. Au lieu d'attendre, j'ai préféré prendre les devants et regarder les specs pour voir comment ces composants pouvaient m'être utiles. Les specs sont assez complètes et l'on trouve même les interfaces détaillées (au sens programmatique et au sens graphique). J'ai au départ commencé à faire "mon propre Hero" à partir des specs mais j'ai vite buté sur certains points qui sont, à mon avis, bloquants.

Dans ce billet, je vais présenter l'approche Hero ainsi que celle que j'ai mis en place pour les comparer. Le but est aussi que vous me donniez votre avis, n'hésitez donc pas à utiliser les commentaires !

L'approche Hero

Comme je l'ai dit plus haut, l'approche Hero est bien décrite dans les specs. Mais si vous n'avez pas envie de les lire, mieux vaut faire un petit recap.

On a deux composants principaux: View et ViewNavigator. Une View est un objet graphique représentant un écran de votre application. Un ViewNavigator représente un objet logique, qui va gérer les View.

Le composant ViewNavigator

Le composant ViewNavigator peut facilement être comparé au composant mx:ViewStack. En effet, celui-ci permet la navigation entre des écrans, avec en permanence, une et une seule vue affichée, celle qui est la plus "haut" dans la pile. Mais la plus grande différence est que ViewStack va contenir des enfants graphiques alors que ViewNavigator est un simple objet logique. Les View ne sont pas des enfants de ViewNavigator, elles sont juste traitées par le ViewNavigator.

Pour ajouter une View au ViewNavigator, il faut lui passer la classe de la View (typiquement, un composant qui hérite de View). On ne lui passe pas une instance mais bien une référence vers la classe.

Par exemple, je crée une View nommée MyView.mxml:

<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
        xmlns:s="library://ns.adobe.com/flex/spark"
        title="View">

    <s:layout>
        <s:VerticalLayout />
    </s:layout>

    <s:Button label="Push" click="navigator.pushView(MyView)"/>

    <s:Button label="Pop" click="navigator.popView()"
        visible="{navigator.length > 1}"
        includeInLayout="{navigator.length > 1}"/>

    <s:Button label="Pop to First View" click="navigator.popToFirstView()"
        visible="{navigator.length > 1}"
        includeInLayout="{navigator.length > 1}"/>

</s:View>

Et voici le code de mon application principale, ne contenant que le ViewNavigator:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark">

    <!-- Create the ViewNavigator and have it display MyView when created -->
    <s:ViewNavigator id="navigator" width="100%" height="100%" firstView="{MyView}"/>
</s:Application>

Dans cet exemple, MyView est passée automatiquement au ViewNavigator car elle est précisée dans le paramètre "firstView". Mais si elle ne l'était pas, on aurait du faire:

navigator.pushView(MyView);

Le ViewNavigator va alors instancier la vue et l'afficher. Pour revenir à la dernière vue (typiquement, la touche Back sur Android), il suffit de faire un navigator.popView(). Le ViewNavigator a en interne, une pile, que l'on peut voir comme un Array. Un "pop()" va supprimer le dernier élément de la pile et la vue qui était auparavant avant-dernière sera affichée.

Passage de données à une vue et sauvegarde de l'état applicatif

A chaque ouverture de vue, on peut passer un objet (non-typé dans l'interface, on peut donc passer n'importe quel objet) afin de lui passer de la donnée pour qu'elle puisse s'initialiser. Par exemple pour une vue qui présente le listing d'un répertoire, on va passer le chemin du répertoire à lister à la vue.

Le composant ViewNavigator se charge lui-même de stocker les données passées aux vues pour permettre à l'application de revenir dans son état précédent si l'application a été "Garbage Collectée" par le système alors qu'elle était réduite (à cause du pseudo-multi-tâche des systèmes mobiles).

Politique de destruction du ViewNavigator

Lorsqu'une nouvelle vue va être affichée, les composants de la vue précédente vont être détruits (comportement par défaut). On peut cependant préciser une "destructionPolicy" pour indiquer s'il ont veut ou non conserver les vues lors de la navigation. Les vues précédentes sont détruite pour libérer la mémoire prise par l'application afin qu'elle soit toujours fluide.

Le composant View

Le composant View représente un écran (graphique, donc). Celui-ci contient en permanence, une référence vers le ViewNavigator qui le gère. Cela permet d'appeler directement un "push" ou un "pop" sur le ViewNavigator pour pouvoir créer la navigation vers une nouvelle vue directement depuis la vue.

Pour une navigation aisée sur environnements mobiles, chaque View pourra contenir une ActionBar. Cette ActionBar est la barre que l'on trouve en haut des écrans des applications iOS. Celle-ci contient 3 éléments:

  • Une partie navigation (bouton pour revenir vers la vue précédente, typiquement)
  • Une partie avec le label de la vue
  • Une partie "actions" dans laquelle seront présents des boutons permettant de faire des actions sur la vue

Ma critique sur l'approche Hero

Après avoir bien étudié cette approche et avoir essayé de la mettre en place dans mon application, j'ai eu le sentiment que celle-ci était, soit inachevée, soit impossible à mettre en place dans une vraie application. Lorsque l'on regarde les exemples, ils sont "trop" simples pour représenter les problématiques que l'on a lorsque l'on fait le développement d'une application plus lourde.

Dans la suite de l'article, je vais donc lister les points qui sont selon moi des points forts ou des frein pour le développement mobile.

Premier bon point: La sauvegarde des données de session

S'il y a un truc que je trouve puissant dans Flex 4.5, c'est la possibilité de sauvegarder l'état de session de l'utilisateur. Celui-ci est sauvegardé automatiquement lorsque l'application perd le focus (quand on repasse sur l'écran d'accueil Android par exemple. Ainsi, si l'application est "killée" par le système pour libérer la mémoire, l'utilisateur peut reprendre là où il en était.

En plus, je viens ce soir de regarder le code est il est vraiment écrit de manière propre et découplée. Ainsi, si vous voulez utiliser ce système de persistance dans un autre contexte, vous pouvez ré-utiliser la classe PersistenceManager ou créer votre propre implémentation de IPersistenceManager.

Deuxième bon point: Des composants prévus pour une interface "touch"

Le framework Flex contient désormais des évènements et des propriétés uniquement pour les interfaces pour touchScreen (même jusqu'à l'intérieur de UIComponent). Ainsi, les Spark List détectent automatiquement ces évènements et gèrent l'inertie et autres effets. Ces composants peuvent donc être ré-utilisés directement dans une application sans ajouter de modification de code.

Premier frein: Le système d'instanciation de vues

Je pense pouvoir assurer que tout Flexeur (même juste un peu expérimenté) a eu un problème assez commun avec les composants ViewStack ou TabNavigator. Celui-ci se produit quand on essaie d'accéder à la propriété d'un composant qui fait partie de la stack mais qui n'a pas encore été visible. En effet, la "creationPolicy" de base des composants ViewStack et TabNavigator fait qu'une vue n'est proprement initialisée (createChildren  + CREATION _COMPLETE) que lorsqu'elle a été affichée au moins une fois. C'est de la "lazy instanciation" pour économiser les ressources prises lors de la création/agencement de composants non visibles, pouvant être lourde.

Mais parfois, on ne veut pas afficher cette vue, on veut juste modifier une de ses variables pour plus tard et on se retrouve à mettre la "creationPolicy" à "all" ou à "queued" pour être sûr de ne pas se prendre un Null Pointer. Et c'est ce qui va se passer avec les View que vous allez utiliser. En effet, on ne travaille jamais avec des instances, mais simplement avec des références de classe qui vont être instanciées à la volée.

On ne peut donc jamais dire que telle View va avoir telle propriété à telle valeur. Pour cela, la seule solution est de passer la propriété en question dans les données qui sont passées au démarrage. Mais la modification que l'on souhaite faire n'est pas forcement liée à la vue courante et pourrait être plus globale. A terme, on va donc avoir un objet "global" que l'on va venir alimenter de diverses manières par différentes View. Et lorsque l'on va vouloir appeler cette View, on va récupérer cet objet et lui passer. C'est la seule manière que je vois, peut-être vous voyez une manière plus propre?

Bref, pour moi, rien que ce système d'instanciation de vues est un handicap énorme à l'utilisation de Hero qui m'a fait préférer mon système :)

Deuxième frein: Une ergonomie pour quel type de smartphone?

Après avoir relu la spec en large et en travers, je me suis posé la question de la portée de ces composants. On retrouve par exemple une ActionBar qui fait penser aux interfaces iOS. Très bien, cela peut me servir si je fais une application pour iOS mais si je fais une application AIR pour Android, je fais comment? Une ActionBar est une ergonomie que l'on ne voit dans aucune des applications Android natives, elle est seulement présente dans les interfaces iOS. Cela permet notamment de gérer une navigation sans avoir de bouton "Back" comme sur Android.

Sur Android, le réflexe est plutôt d'utiliser le bouton hardware "Menu" afin d'afficher un menu contextuel. Ah tiens, le menu? Personne n'en parle dans les documentations? Est-il absent des composants mobiles ? C'est pourtant un composant indispensable présent aussi bien sur Android que sur iOS (menu permanent en bas de vue). Cela semble dire qu'il faudrait en plus développer ses propres composants menu… Pas terrible pour un framework.

Troisième frein: Un code unique pour plusieurs écrans ?

Un des avantages de l'utilisation de AIR pour iOS et Android et qu'il permet d'utiliser la même base de code pour les deux systèmes. Je peux vous garantir que cela sauve un temps incroyable! Le code-once-deploy-to-many est donc plus que jamais d'actualité. Mais avec l'utilisation d'Hero, cela semble plus difficile.

En effet, comme je viens de le dire, les ergonomies suivant les OS sont totalement différentes, ne serait-ce que par la différence hardware (plusieurs boutons sur Android, un seul sur iOS). Cela implique de nombreuses variantes de comportement comme par exemple:

  • Un menu qui vient par dessus l'interface sur Android après appui sur la touche Menu / Un menu permanent sur iOS qui est intégré dans l'interface (il prend de la place)
  • Une navigation par le bouton "Back" sur Android / Une navigation par l'ActionBar sous iOS
  • Un champ de saisie accompagné d'un bouton de validation sous Android / Un bouton Rechercher directement intégré au clavier visuel sous iOS

On peut aussi parler des différences d'interface entre une application destinée à une tablette et une application destinée à un téléphone. Ce ne sont pas les mêmes applications / ergonomie pour un iPhone et un iPad par exemple.

Au delà des différences de comportement, il y a aussi des différences de style. Chaque OS a son style graphique qu'il faut respecter sans quoi les utilisateurs seront perdus.

Hero ne semble pas prendre en compte ces contraintes et sembles se restreindre au "dénominateur commun", iOS, qui ne dispose pas de boutons hardware. C'est vraiment dommage et dans le cas du développement d'une application mobile, bloquant.

Quatrième frein: Mix de mes composants Flex 3 avec du Flex 4

Bon, celui-là est plus "perso" mais me posait aussi problème. Certains vont dire que je suis un papy du Flex mais je travaille toujours avec Flex 3. Tout simplement car toute la base de code que j'utilise est en Flex 3 et que je n'ai pas le temps matériel de faire une migration propre. Vue qu'une View est par exemple basée sur Group (Flex 4), cela ferait un mix entre du Flex 3 et 4 qui ne me plait pas vraiment. Ok, ces composants viennent avec Flex 4.5, il est donc logique qu'ils soient basés sur Flex 4. N'empêche que cela m'embête :P .

Conclusion personnelle sur l'approche Hero

Voilà mon avis sur ces composants mobile du prochain SDK Flex. Ce n'est bien sûr que mon avis, basé sur les spécifications encore incomplètes sur des composants pas encore terminés / testés, cela peut donc s'arranger (ou pas) dans le futur. Les quatre points que j'évoque plus haut sont pour moi, tous bloquants dans mon processus de développement d'application mobiles.

Au lieu d'attendre et d'être déçu, j'ai donc décidé de me retrousser les manches et de développer mes propres composants mobiles pour Flex. Il ne faut pas y voir une volonté "typiquement développeur" de vouloir réinventer la roue mais bien une démarche constructive car pour moi, Hero ne représente pas la roue, tout juste un barreau.

Je suis (selon moi) allé bien plus loin dans la réflexion et dans l'architecture des composants ainsi que sur la facilité de développement de ceux-ci. Le but n'était pas de faire un framework super abstrait mais bien un outil de développement puissant et rapide pour coder des applis mobile.

Bon, finalement ce billet est bien plus long que ce que je pensais, je vous réserve donc un billet sur l'approche que j'ai prise pour la prochaine fois !

Si vous avez un avis différent (ou qui rejoint le mien), n'hésitez pas à laisser un commentaire (c'est gratuit!), j'aimerai beaucoup échanger avec vous tous :)

opensource.adobe.com/

Articles similaires

Commentaires (8) Trackbacks (1)
  1. J'ai le sentiment que Flex mobile est vraiment basé sur une approche MVC, et que du coup, une partie des points que tu soulèves sont annulées avec une architecture de ce type.
    Car en fait, ne pense tu pas que si tu as besoin de changer une variable dans une view qui n'est pas encore instanciée, c'est en fait le modèle que tu devrais mettre à jour, et ta vue aura la bonne valeur au bon moment?
    Moi je trouve que pour ceux qui veulent faire du bon développement multiscreen, les composants Sparks sont indispensables, et un bonne micro-architecture aussi. Je suis en train de tester pas mal Robotlegs, et je trouve que ça se marrie très bien avec le développement mobile (notamment car tes vues reçoivent leur données par Dependency Injection, donc tu ne te soucie pas de les transmettres toi même…

    Sinon, j'ai pas encore assez testé Hero, donc je donnerai mon avis plus tard… En attendant de voir tes propositions aussi ;)

  2. Salut et merci pour ton commentaire :)
    Effectivement, certains framework faisant de l'injection de dépendance comme Robotlegs ou Swiz peuvent remédier au fait que les vues ne sont pas instanciées directement car elles vont faire le boulot d'instanciation et de de population des views. Mais cela me semble toujours un peu trop magique et difficile a maitriser.
    Pour les variables qui modifient une vue, cela va bien plus loin que cela, les prop de style ou de paramétrage par exemple n'ont pas leur place selon moi dans le model et pourtant, il te faudra bien les mettre quelque part sinon lors de la récupération, ton appli sera dans un état différent.
    Je publie demain une vidéo de mes résultats

    Fabien

  3. bonjour,

    Je te félicite pour la qualité de ton travail (formalisme, pédagogie…), que je consulte tous les jours afin de suivre l'essentiel de la technique flex, flash
    Je trouve que ta critique de Hero est argumentée… (bien que je ne sois pas un expert 3ème dan)

    Comme ton travail est réellement très constructif,j'avais une question :
    As tu fais part de ton travail et de ton analyse à l'équipe Adobe US ??
    Si ce n'est pas le cas, tu devrais vraiment le faire, afin de faire avancer le smillblick
    et de challenger la réactivité des gens d'Adobe

    Xavier

  4. Salut Xavier et merci pour ton feedback.

    Je n'ai pas (encore) fait part de mon travail à Adobe, je voulais déjà avoir un feedback des lecteurs de flex-tutorial comme toi ou Dimitri pour savoir si j'étais dans le vrai ou pas.
    Ce soir sera publiée une petite vidéo qui présente les résultats que j'ai obtenu, dans les prochains billets, je vais présenter l'architecture que j'ai préparé. Si le feedback général est bon, j'en ferai part à Adobe

    Merci,
    Fabien

  5. Quelques remarques pour contraster un peu avec les points énumérés dans cet article :

    1) Le système d'instanciation de vues

    Ce système me convient assez bien. L'idée est bien de stocker quelque part des valeurs par défaut pour une vue qui n'existe pas encore. Quand cette vue est instanciée et ajoutée au stage, soit elle tire ces données (lookup) , soit elle se les fait injecter (injection…). Il est vrai que les frameworks de type ioc aident bien à ce moment là.

    2 et 3) Une ergonomie pour quel type de smartphone?/ Un code unique pour plusieurs écrans ?

    A priori le menu devrait quand même être intégré aussi dans hero si l'on se réfère à cet article : http://insideria.com/2010/10/building-a-native-menu-in-flex.html.

    Si c'est bien le cas, on aura moins l'impression qu'ils "collent" au modèle iOS.
    De mon point de vue, je pense qu'il est préférable d'adapter l'interface ainsi que l'expérience utilisateur à chaque mobile plutôt que de faire une application identique pour chaque support.

    Attention, il s'agit d'une version beta donc on peut s'attendre à des changements, évolutions, ajout de fonctionnalités, dont certains imprévus. Personnellement, à moins de contraintes de timing fortes, j'attendrais un peu avant de partir sur un développement custom (et à ce moment là, j'aurai tendance à prendre une approche pure AS3 plutôt que Flex, surtout si c'est le 3)

  6. Salut Florian, merci d'avoir pris le temps de lire l'article et de rédiger un commentaire :)

    Le système d'instanciation de vue est vraiment bon d'un point de vue théorique mais difficile (selon moi) à appliquer correctement en pratique, à moins d'y greffer en plus un framework ioc.

    Pour le menu, cela sent un peu la spéculation (j'avais aussi lu l'article qui est paru un peu après le mien). Tous les composants qu'ils ont sorti avaient des specs bien précises (ViewNavigator, View, ActionBar & co) et rien sur un "Menu" mobile, je doute encore que ce soit pour la version finale (on peut faire une application sans, ce n'est pas critique).
    Je suis complètement d'accord sur le fait que l'interface utilisateur doit être adaptée à chaque OS, les applications "identiques" sont vite décriées par les utilisateurs dans les commentaires (cf. application TCL sur Android avec look iOS).

    Comme tu le dis, c'est une beta, on peut s'attendre à des imprévus :)

    Fabien

  7. Mon modeste avis rejoint en certains points le tiens.
    Venant du monde microsoft, (application desktop etc…) j'ai franchis le pas Flex il y a 6 mois avec la V3, puis la V4 et depuis peu Air.
    Je suis convaincu que 2011 et la suite va voir l'avènement des tablettes et consort et je n'ai aucun a priori sur les OS ou marques de matériel mais je pense que chacun essaye de ne pas se fermer des perspectives de développement. Cependant nous sommes tous assez tributaires des marchés économicos-informatique et devons faire avec ce que l'on nous fourni. Assez de blabla !!!
    N'étant pas non plus un Ninja du sujet, j'ai eu l'impression d'avoir (avec Hero) un remix assez Hypercard (Apple) des années 80. Le modèle pré-maché d'adobe me gène un peu tant sur les possibilités visuelles que sur les perspectives créatrices. C'est à mon avis un premier jet d'Adobe, du style "on fourni rapidement des outils (assez simples) pour marquer notre empreinte sur le terrain du mobile" et du mobile seul dans un premier temps. Je pense également qu'Adobe est poussé par les fournisseurs de tablettes et mobiles afin de stopper ou ralentir Apple.
    Ce qui m'inquiète le plus c'est le concept de "mobile" chez Adobe. Considèrent t-ils le téléphone comme une tablette ? Autant comparer un lecteur MP3 avec un chaine Hifi. Ecouter du MP3 sur une chaine Hifi c'est de l'hérésie. Utiliser une tablette 7,8,9,ou 10" avec une appli conçue pour un de téléphone portable, c'est aussi n'importe quoi. Ne serait-ce que par la différence de la taille écran l' "expérience" utilisateur (très en vogue cette expression) n'est pas du tout la même.
    Donc en conclusion :
    Pour mobile :
    + pseudo universalité, première approche facile.
    - contrainte de dév trop pénalisante à terme
    Pour tablette :
    + pseudo universalité
    - composants pas adaptés et trop peu nombreux

    Ah oui, je signe tout de suite la pétition pour faire part de ton expérience à Adobe.

    Gilles

    PS :
    Hyper bravo pour les articles parus, qui sont un support efficace, surtout pour moi qui suis arrivé dans ce monde avec des lacunes plus grandes que mon ignorance, mais je me soigne.
    Merci encore.

  8. Bonjour Gilles et merci pour votre commentaire.
    Je suis actuellement en train de réfléchir à l'adaptation de mon modèle applicatif à celui des tablettes. Cela change pas mal de choses (plusieurs vues visibles à un instant T, 2 le plus souvent) et rien que cela implique pas mal de modifications.
    Par exemple pour le menu. On le verra dans un prochain tutorial, chaque vue définit des éléments de menu qui lui sont associés. Quand on a 2 vues affichées, que faut-il proposer à l'utilisateur? Le plus cohérent serait de proposer un menu combiné (merge) en supprimant les commandes permettant de revenir à une vue déjà affichée.
    Bref, il faut que le système s'occupe de "détails" comme cela. Je suis en train de faire justement une application (POC) pour Business Geografic sur tablette (on va essayer sur iPad), c'est le bon moment pour mettre la théorie en pratique :)

    Fabien


Leave a comment

(required)