2012/08/24

The Application of Modularized TWaver Flex Application

The more widely-used Flex is; the more problems will thus rise:
  1. The size of SWF files will become larger;
  2. It will cost longer time to download SWF files;
  3. If there are several Flex applications, then how to multiplex the same codes (including Flex Framework, customized component library and third-party packages, such as TWaver Flex );
  4. Users need to download the new SWF file again after every update;
  5. How to add the new functions without revising and editing the old SWF files.
How to solve these problems?
Firstly, Runtime Shared Libraries can be used. The Flex Framework, the customized component libraries and the third-party packages are all separate swf files. The codes for them will not be included in Flex application programs, so:
  1. Just update the codes for new users’ programs, instead of updating Flex Framework, customized component libraries and third-party packages after the program is revised;
  2. RSL is buffered by the browser: it is not necessary to download RSLagain after updating the user program;
  3. There is no need to download repeatedly since a RSL can be shared by several Flex applications.
Secondly,modularity can be used.Function modules are divided into different SWF files, so:
  1. Able to update a specified function module separately;
  2. Able to dynamically add modules.
However, the problems will not be solved if just use RSL or Modularity:
  1. The function modules cannot be divided and they also cannot be loaded dynamically if only RSL is used.
  2. The shared Flex Framework, customized component libraries and the third-party package used in all modules are not able to be deleted if only using Modularity, hence the oversize of the sub-modular files.
In this article we will introduce the combination of RSL and Modularity in detail and help you to make modularized, extensible and powerful TWaver Flex application.
To begin with,in order to avoid the high coupling between the main program and the sub-module, we need to create a Flex Library project which has defined all public classes used in sub-modules and the interface of the communication between the sub-modules and the main program.
  1. IModule interface: the sub-module’s realization of this interface is used to show the name of it in the main program (get title), and call back it after the loading of it is finished (ready).
  2. package demo {
        public interface IModule {
            function get title():String;
            function ready(app:IApplication):void;
        }
    }
     
  3. IApplication interface is realized by the main program, used in the interaction between the sub-module and the main program. Now there is no method in this interface. You can add your own methods according to your requirement.
  4. package demo {
        public interface IApplication {

        }
    }
     
In addition, Library project has also customized the Network components and Node to the use of sub-module. But you need to pay attention to the fact that the link type of framework linkage and twaver.swc must be changed to external in the project selections in order to reduce the size of the sec files generated by Library project.
Next, create the main program--Flex project which uses the Library project above and twaver.swc. Its function is to show Tree on the left side and after clicking the tree node, the corresponding sub-module will be loaded on the right side.
  1. Add the component’s label and initialize the interface. First is HDivededBox component. Left: FastTree, right: VBox. (In VBox) up: Label, showing the name of the sub-module, bottom: sub-module container.
  2. <mx:HDividedBox width="100%" height="100%">
        <tw:FastTree id="tree" width="300" height="100%"/>
        <mx:VBox width="100%" height="100%">
            <mx:Label id="title" width="100%" textAlign="center"/>
            <mx:Canvas id="content" width="100%" height="100%"/>
        </mx:VBox>
    </mx:HDividedBox>
     
  3. Initialize the tree node: in order to succeed to dynamically add modules, here we read the information on modules from xml files. If you need to add new modules, you can change xml files directly instead of changing the main program.
  4. Xml file includes the name and the url of the module: 
      <modules>
          <module name="PSTN" url="ModulePSTN.swf"/>
          <module name="Alarm" url="ModuleAlarm.swf"/>
      </modules>
    Load codes for xml files as follows to save url information into the “client” property and to use this url to load the sub-module when clicking this node. 
    private function initTreeBox():void {
        var httpService:HTTPService = new HTTPService();
        httpService.resultFormat = "e4x";
        httpService.addEventListener(ResultEvent.RESULT, this.addModules);
        httpService.url = "modules.xml";
        httpService.send();
    }

    private function addModules(e:ResultEvent):void {
        for each(var module:XML in e.result.module){
            this.addModule(module.@name, module.@url);
        }
    }

    private function addModule(name:String, url:String):void {
        var data:Data = new Data();
        data.name = name;
        data.setClient("url", url);
        this.tree.dataBox.add(data);
    }

  5. Add the listener which listens to the selection of the nodes in Tree: When a node in Tree is selected, we first judge whether the corresponding sub-module has been loaded or not. If not, it will be dynamically loaded, and then saved into the “client” property; if it has already been loaded, the sub-module previously saved in the “client” property will be directly added into the container at the right side:
  6. this.tree.selectionModel.addSelectionChangeListener(this.handleSelectionChangeEvent);

    private function handleSelectionChangeEvent(e:SelectionChangeEvent):void {
        var selectedData:IData = this.tree.selectionModel.lastData;
        if(selectedData){
            var moduleLoader:ModuleLoader = selectedData.getClient("module");
            if(moduleLoader){
                this.content.removeAllChildren();
                this.content.addChild(moduleLoader);
                this.title.text = (moduleLoader.child as IModule).title;
            }else{
                moduleLoader = new ModuleLoader();
                moduleLoader.percentWidth = 100;
                moduleLoader.percentHeight = 100;
                moduleLoader.addEventListener(ModuleEvent.READY, this.moduleReady);
                moduleLoader.loadModule(selectedData.getClient("url"));
                selectedData.setClient("module", moduleLoader);
            }
        }
    }

    private function moduleReady(event:ModuleEvent):void {
        var moduleLoader:ModuleLoader = event.target as ModuleLoader;
        var module:IModule = moduleLoader.child as IModule;
        content.removeAllChildren();
        content.addChild(moduleLoader);
        this.title.text = module.title;
        module.ready(this);
    }
     
Notice that when importing twaver.swc and Library project, twaver.swc must be above the Library project, or it will complains: couldn’t find the class twaver.network::Network. In addition, the link type of framework linkage, twaver.swc and the Library project just mentioned above must be Runtime Shared Library(RSL). Please see the third step in the following for how to set in detail:

At last, please notice that when importing twaver.swc and Library project, twaver.swc must be above the Library project, or it will complains: couldn’t find the class twaver.network::Network. In addition, the link type of framework linkage, twaver.swc and the Library project just mentioned above must be Runtime Shared Library(RSL). Please see the third step in the following for how to set in detail:
Moreover, the compiling path of the sub-module can be changed to the catalogue of bin-debug of the main-program project. In this way, you don’t need to replicate the sub-module swf to the bin-debut of the main program after changing the sub-module every time.

Furthermore, it is unnecessary to generate HTML Wrapper, for the sub-module cannot be run independently. It can only be loaded from the main program. So there is no need to generate the html file which wraps sub-modules:
Finally, please notice that when changing link type to RSL, the OK button cannot be clicked only after you add RSL path, or you can just click “Add” button.
The codes for the sub-module is quite simple, but you need to pay attention that the root tab of mxml files must be changed to Module and the IModule interface must be realized.
<?xml version="1.0" encoding="utf-8"?>
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns:demo="http://www.demo.com/demo" implements="demo.IModule"
    xmlns:tw="http://www.servasoftware.com/2009/twaver/flex"
    creationComplete="init()" width="100%" height="100%">
<mx:Script>
<![CDATA[
    import demo.*;

    private var _app:IApplication = null;

    public function get title():String {
        return "Alarm Demo";
    }

    public function ready(app:IApplication):void {
        this._app = app;
    }
]]>
</mx:Script>
</mx:Module>
We can last test the program after the procedures above:
Now let’s see the size of the package including the sub-modules, Library project and the main program. (It is really small-sized for the sub-module only is only less than 50K.)
Please refer to the official document of Adobe for more information on Module and RSL:
Creating Modular Applications
Using Runtime Shared Libraries

No comments:

Post a Comment