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

19oct/097

Flex Modules – Communication découplée entre modules avec EventBroker

On l'a vu dans les articles précédents, la communication avec les modules Adobe Flex peut se révéler difficile s'il on essaie de découpler complètement les modules de l'application Flex. Pour cela, on peut utiliser une interface ActionScript qui va permettre de brider la transaction à certaines méthodes identifiées. Cette méthode permet déjà de découpler le module de l'application de manière significative. Mais pour une communication dans les deux sens, cela peut devenir assez coûteux.

Une solution que j'utilise en environnement professionnel consiste à se servir de l'excellente classe EventBroker de Development Arc. Celle-ci permet en effet d'utiliser le Design Pattern Mediator pour avoir un objet commun (Singleton Facade) qui va s'occuper uniquement du transit des évènements dans l'application. Cette classe que vous pouvez utiliser simplement dans votre application va nous servir de point d'entrée pour la communication module/application ou application/module ou même module/module.

En utilisant simplement cette classe et quelques évènements personnalisés, vous pourrez créer cette communication de manière aisée. Voyons un petit d'exemple d'application:

Application Principale

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Script>
    <![CDATA[
      import events.ApplicationEvent;
      import mx.controls.Alert;
      import events.ProductTypeSelectionEvent;
      import util.EventBroker;

      private function onFirstModuleReady():void {
        EventBroker.subscribe(ProductTypeSelectionEvent.USER_SELECTION, onProductSelectionEvent);
      }

      private function onProductSelectionEvent(event:ProductTypeSelectionEvent):void {
        var selectedItem:String = event.selectedItem;
        Alert.show("Application::Selection dans le Module FirstModule: " + selectedItem);
      }

      private function onSendEventToModules():void {
        var selectedNumber:int = magicNumberStepper.value;
        var event:ApplicationEvent = new ApplicationEvent(ApplicationEvent.ON_MAGIC_NUMBER, selectedNumber);
        EventBroker.broadcast(event);
      }
    ]]>
  </mx:Script>
  <mx:HBox width="100%"
           height="100%">

    <mx:Panel title="Application Principale"
              paddingLeft="10"
              paddingRight="10"
              paddingTop="10">
      <mx:Text text="Le nombre choisi sera envoyé vers les deux modules par un evènement de type ApplicationEvent"
               width="350"/>
      <mx:Button label="Envoyer un Event depuis l'application"
                 click="onSendEventToModules();"/>
      <mx:NumericStepper id="magicNumberStepper"
                         value="38"/>
    </mx:Panel>
    <mx:ModuleLoader url="FirstModule.swf"
                     ready="onFirstModuleReady();"/>
  </mx:HBox>
  <mx:HBox width="100%"
           height="100%">
    <mx:ModuleLoader url="SecondModule.swf"/>
  </mx:HBox>
</mx:Application>

Pour cette application de démonstration, on écoute un évènement de type ProductTypeSelectionEvent.USER_SELECTION qui sera envoyé par un module. Au clic sur le bouton, on va envoyer en broadcast, un évènement de type ApplicationEvent.ON_MAGIC_NUMBER, qui va contenir le nombre choisi dans le NumericStepper.

Module 1: FirstModule.swf:

<?xml version="1.0" encoding="utf-8"?>
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"
           width="400"
           height="300"
           creationComplete="onCComplete();">

  <mx:Script>
    <![CDATA[
      import events.ApplicationEvent;
      import util.EventBroker;
      import events.ProductTypeSelectionEvent;

      private function onCComplete():void {
        EventBroker.subscribe(ApplicationEvent.ON_MAGIC_NUMBER, onNumberReceived);
      }

      private function onNumberReceived(event:ApplicationEvent):void {
        nSFirstModule.value = event.magicNumber;
      }

      private function onChange():void {
        if (singleValuesList.selectedIndex == -1) {
          return;
        }
        var selectedItem:String = String(singleValuesList.selectedItem);
        var event:ProductTypeSelectionEvent = new ProductTypeSelectionEvent(ProductTypeSelectionEvent.USER_SELECTION, selectedItem);
        EventBroker.broadcast(event);
      }
    ]]>
  </mx:Script>
  <mx:Panel title="FirstModule.swf">
    <mx:Text width="250"
             text="Sélection envoyée vers l'application"/>
    <mx:List id="singleValuesList"
             rowCount="4"
             allowMultipleSelection="true"
             change="onChange();">
      <mx:dataProvider>
        <mx:Array>
          <mx:String>Home</mx:String>
          <mx:String>Computers</mx:String>
          <mx:String>Auto</mx:String>
          <mx:String>Electro</mx:String>
        </mx:Array>
      </mx:dataProvider>
    </mx:List>
    <mx:Text width="250"
             text="Nombre envoyé depuis l'application"/>
    <mx:NumericStepper id="nSFirstModule"/>
  </mx:Panel>
</mx:Module>

Ce premier module va envoyé un évènement de type ProductTypeSelectionEvent.USER_SELECTION quand l'utilisateur fait une sélection dans la List. Cet évènement sera écoute à la fois par l'application principale, mais aussi par le second module.

Module 2: SecondModule.swf

<?xml version="1.0" encoding="utf-8"?>
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"
           width="400"
           height="300"
           creationComplete="onCComplete();">
  <mx:Script>
    <![CDATA[
      import events.ProductTypeSelectionEvent;
      import util.EventBroker;
      import events.ApplicationEvent;

      private function onCComplete():void {
        EventBroker.subscribe(ApplicationEvent.ON_MAGIC_NUMBER, onNumberReceived);
        EventBroker.subscribe(ProductTypeSelectionEvent.USER_SELECTION, onProductSelectionEvent);
      }

      private function onNumberReceived(event:ApplicationEvent):void {
        nSFirstModule.value = event.magicNumber;
      }

      private function onProductSelectionEvent(event:ProductTypeSelectionEvent):void {
        var selectedItem:String = event.selectedItem;
        moduleInput.text = selectedItem;
      }
    ]]>
  </mx:Script>
  <mx:Panel title="SecondModule.swf"
            paddingTop="10"
            paddingLeft="10"
            paddingRight="10"
            paddingBottom="10">
    <mx:Text width="250"
             text="Nombre envoyé depuis l'application"/>
    <mx:NumericStepper id="nSFirstModule"/>
    <mx:Text width="250"
             text="Sélection envoyée depuis le module FirstModule"/>
    <mx:Label fontWeight="bold"
              id="moduleInput"/>
  </mx:Panel>
</mx:Module>

Le dernier module de l'exemple, qui va recevoir des évènements envoyés depuis l'application et le premier module.

Application en ligne

Flex Source Code Download: Télécharger le code source complet de l'application

This movie requires Flash Player 11

Conclusion

A travers cette petite application, on a pu voir comment créer des modules communiquant simplement avec des évènements. On voit facilement que la classe EventBroker sert ici de pont dans l'application. Dans un projet mieux organisé, vous pourriez avoir par exemple une Flex Library commune comprenant les Events et les constantes utilisées par EventBroker. Vous pourrez ainsi facilement découper votre application / modules en plusieurs projets sans conflits et avec un couplage très faible entre les classes.

Articles similaires

Commentaires (7) Trackbacks (0)
  1. Salut,

    Je ne parviens pas a utiliser la fonction unsuscribe de EventBroker.
    Je pense qu'elle pourrait m'aider car j'ai un bug dans une de mes appli. et j'ai l'impression que mes eventBroker sont dans une sorte de file d'attente.

    Concrètement :
    - j'ouvre un popup (avec popupmanager) puis je le referme (et cela plusieurs fois)
    - j'ouvre le popup une dernière fois et sur l'evenement click d'un bouton je fais eventbroker.broadcast(new monEvent(monEvent.TOTO);.
    sur l'init de mon popup je fait un eventbroker.suscribe(monEvent.TOTO,mafunction)

    A ce moment la fonction maFunction est appelé autant de fois que le nombre de popup précédemment ouvert.
    Je ne sais pas si cela viens de mes instances de popup qui sont conservées ou si c'est mon utilisation de EventBroker.

    Une idée ?

  2. Salut,
    a mon avis, cela bien du fait que tu t'inscri autant de fois que tu crées des popups. Donc soit au lieu de fermer / ouvrir tes popups, tu les rend simplement invisibles ou alors au moment de la fermeture, tu te desinscris de ton EventBroker

    Have fun
    Fabien

  3. Merci pour ta réponse .

    La désinscription de mon eventBroker ne semble pas fonctionner.
    Je fais :
    EventBroker.unsuscribe (monEvent.TOTO, autreFunction)
    et si je fait un trace dans autreFunction je n'ai jamais rien.

    Je l'utilise mal ?

    Nico.

  4. On dirait que c'est correct. Il faut bien que ton autreFonction soit la fonction a laquelle tu t'es inscrit au départ (pas celle d'une nouvelle popup par exemple, lors de la création d'une pop-up, tu auras un nouveau scope)

    Fabien

  5. Bonsoir fabien,

    Je rencontre le même problème que Nico à la différence que c'est mon contrôleur qui exécution maFunction. Du coup je ne sais pas ou placer le code de désinscription .
    Dois je le placer après l'envoi de l’événement dans ma popup ou après l’exécution de la fonction dans mon contrôleur ?

    Eddoh

  6. Salut,
    Placer le code de désinscription dès que l'évènement a été reçu

    Fabien

  7. Ça marche,

    Merci beaucoup fabien.

    Eddoh


Leave a comment

(required)

Aucun trackbacks pour l'instant