ActionScript
Using Modules In Flex Action Script Projects
October 22, 2010
0

Using modules enhances scalability (i.e.: your application code does not have to reside in one swf, which quite possibly will grow very large as features are being added).  In this tutorial, we explores how to create and load a Module in a Flex Builder Action Script project.

Create an Example Project

Create a new Action Script Project, name it SimpleLoadingModuleExample.

Note: This example is using Flex Builder 3 with Flex SDK 3.3, however the principle can be used with Eclipse using the Flex SDK. We are using Action Script project for this example, although Module is also supported in MXML projects.

1. Creating the Module class.

There are several ways to create a Module class, the one described here uses [Frame(factoryClass=”mx.core.FlexModuleFactory”)] which is less straightforward than using ModuleBase class, but more flexible.  This method requires at least one ‘base’ class which class cannot be instantiated by the factory, so you need to derive your module classes from this ‘base’ class.

So let’s say I want to have several modules that derives from MovieClip, let’s create the base class, save it as MovieClipModuleBase.as


package
{
  import flash.display.MovieClip;

  [Frame(factoryClass="mx.core.FlexModuleFactory")]
  public class MovieClipModuleBase extends MovieClip
  {
  }
}

The key information here is the line [Frame(factoryClass=”mx.core.FlexModuleFactory”)] above the class declaration, which tells the compiler that this class can be instantiated by the module factory. However as mentioned before, you cannot instantiate this class using the factory, and instead we need to derive from this class. So,then, let’s create the derived class.

For this example, it will just be a simple movie that draw a circle. Let’s call is MovieClipModule.as


package
{
  import flash.display.MovieClip;

  public class MovieClipModule extends MovieClipModuleBase
  {
    public function MovieClipModule():void
    {
      super();

      this.graphics.clear();
      this.graphics.beginFill(0xff0000);
      this.graphics.drawEllipse(0,0,500, 500);
      this.graphics.endFill();
    }
  }
}

As you see, this bare-bone example simply extends the MovieClipModuleBase and draws a circle on itself.

2. Loading the Module.

We are going to use ModuleManager to load modules. In this basic example, I am just going to load the module then add it into into the main application canvas. The class name of my example is a boring name of SimpleLoadingModuleExample.

You will see here that the example is straightforward (except for some weird gotchas) for illustration purpose and it is not a good example of Module utilization. In a real application, you would want to create a class to manage (load/unload/communicate) between modules, otherwise why use modules?

Here’s the skeleton of the main application class.

package
{
  import flash.display.MovieClip;
  import mx.modules.IModuleInfo;
  import mx.events.ModuleEvent;
  import mx.modules.ModuleManager;
  import flash.events.Event;
  import mx.events.FlexEvent;
  import mx.modules.ModuleManager;
  import mx.core.IFlexModuleFactory;

  [SWF(width='500', height='500', backgroundColor='#FFFFFF', frameRate='30')]
  public class SimpleLoadingModuleExample extends MovieClip
  {
    public function SimpleLoadingModuleExample()
    {
    loadModule();
    }

    public function loadModule()
    {
      var moduleURL:String="MovieClipModule.swf";
      var moduleInfo:IModuleInfo=ModuleManager.getModule(moduleURL);
      moduleInfo.addEventListener(ModuleEvent.READY, onModuleReady);
      moduleInfo.load();
    }

    public function onModuleReady(event:ModuleEvent):void
    {
      var moduleInfo:IModuleInfo=event.module;
      var factory:IFlexModuleFactory=event.module.factory;
      var module:MovieClipModule=factory.create() as MovieClipModule;
      addChild(module);

    }
  }
}

The above code shows the very simplest form of the loadModule() function.

var moduleURL:String="MovieClipModule.swf";
var moduleInfo:IModuleInfo=ModuleManager.getModule(moduleURL);
moduleInfo.addEventListener(ModuleEvent.READY, onModuleReady);
moduleInfo.load();

The above code will not work (at least in Flex 3.0 SDK) because ModuleEvent.READY never gets fired and it is because moduleInfo becomes out of scope as soon as the function exits. You need to hold a reference to the moduleInfo to make it not go out of scope, otherwise it will not fire the ModuleEvent.READY. For best practices, you can create a manager class to do this, but for now, let’s just revise the code so that the moduleInfo is referenced by our sample application (i.e.:using a member variable). I name it mModuleInfo in the example below:

package
{
  import flash.display.MovieClip;
  import mx.modules.IModuleInfo;
  import mx.events.ModuleEvent;
  import mx.modules.ModuleManager;
  import flash.events.Event;
  import mx.events.FlexEvent;
  import mx.modules.ModuleManager;
  import mx.core.IFlexModuleFactory;

  [SWF(width='500', height='500', backgroundColor='#FFFFFF', frameRate='30')]
  public class SimpleLoadingModuleExample extends MovieClip
  {
    private var mModuleInfo:IModuleInfo=null;

    public function SimpleLoadingModuleExample()
    {
      var moduleURL:String="MovieClipModule.swf";
      mModuleInfo=ModuleManager.getModule(moduleURL);
      mModuleInfo.addEventListener(FlexEvent.LOADING, onModuleLoading);
      mModuleInfo.addEventListener(ModuleEvent.SETUP, onModuleSetup);
      mModuleInfo.addEventListener(ModuleEvent.READY, onModuleReady);
      mModuleInfo.addEventListener(ModuleEvent.ERROR, onModuleError);
      mModuleInfo.addEventListener(ModuleEvent.PROGRESS, onModuleProgress);
      mModuleInfo.addEventListener(ModuleEvent.UNLOAD, onModuleUnload);
      mModuleInfo.load();
      //trace("loadModule "+moduleURL);

    }

    public function onModuleSetup(event:ModuleEvent):void
    {
      trace("onModuleSetup");
    }

    public function onModuleLoading(event:FlexEvent):void
    {
      trace("onModuleLoading");
    }

public function onModuleReady(event:ModuleEvent):void
{
  // Yes I could have used mModuleInfo here but I didn't, to illustrate the point that
  // the info can be retrieved from the event (so that if you're loading multiple modules, less  bookeeping for you)
  var moduleInfo:IModuleInfo=event.module;
  var factory:IFlexModuleFactory=event.module.factory;
  var module:MovieClipModule=factory.create() as MovieClipModule;
  addChild(module);

}

public function onModuleError(event:ModuleEvent):void
{
  trace("onModuleError "+event.errorText);

}

public function onModuleProgress(event:ModuleEvent):void
{
  trace("onModuleProgress "+event.bytesLoaded/event.bytesLoaded*100+"%");
}

public function onModuleUnload(event:ModuleEvent):void
{
  trace("onModuleUnload");
}
}
}

PS: While at it, I also added several more ModuleEvent listeners. You can find out what these do from the doc: http://www.adobe.com/livedocs/flex/201/langref/mx/events/ModuleEvent.html The ModuleEvent.ERROR is particularly useful for debugging if your module doesn’t load.

IModuleInfo also has a data field. If you need to pass data to the module, you can use this variable prior to calling moduleInfo.load.

Telling Flex which classes are Module.

We’re almost ready to run the example but first we need to tell Flex Builder to compile our Module as SWFs.

Go to the Project Properties -> Action Script ModulesSelect the class by clicking the Browse button.   Note that if your module is outside of the main package, then the swf will be compiled under the same package structure.

Goto your bin-debug folder (or wherever the project output folder is), and you should see two SWF files created during compilation:

  • SimpleLoadingModuleExample.swf  (the main application)
  • MovieClipModule.swf

Run The Example


You should see a red circle indicating that the module is loaded.

Again, this is just an example of how to create and load a Module. In a real application, it is a good practice to keep the main application as a shell that loads and unloads modules as necessary.

Download Flex Builder Project Example.
Continue to Loading And Unloading Modules.