Tuesday, February 9, 2010

Dear John, what is the easiest way to use Flex modules?

Question asked by Ezra.
When it comes to modules there are two general schools of practice:
  1. Load and cache
  2. Load and unload
Option 1 is by far the most simple, but since content is never unloaded the application has to be small enough to theoretically be loaded in its entirety. I tend to build most Flex applications under this model.
Option 2 is near impossible depending on the specific implementation. There are many areas beyond what I have written about that can prevent a module from from unloading. I have built applications under this model, and getting things to unload correctly is a massive undertaking.
Implementing option 1 can be as simple as putting a view stack in your main application file and using states to add ModuleLoaders to it, and as complicated as writing your own module manager utility to load modules based on some external configuration.
An important concept with modules that you must always consider though is compile by reference. When compiling a Flex application into a SWF file, it is that class which inherits from “mx.core.Application” and the referenced classes within its class hierarchy that are compiled into that SWF file along with other embedded resources. Classes that are not referenced in that class hierarchy are not compiled into the application SWF file. This concept of compilation by reference in a Flex application also applies to a Flex module.
Knowledge of compilation by reference and their effects on modules and applications is important, because if an application has reference to a module class in its class hierarchy that module class is compiled into both the module SWF file and application SWF file. This duplication of module class definitions is undesired behavior, since the main purpose of modules is to have code and resources in a location outside of the application SWF file and not within it. Beware that the several examples I have seen in Adobe documentation and elsewhere show the main application give direct reference to the module class that it is trying to load. This results in that module class being compiled into both the main application SWF and the module SWF, which defeats the purpose of using modules.
Modules are also effected greatly by optimization by eliminating class duplication. For example if your main application, ModuleA, and ModuleB reference FOO, if ModuleA and ModuleB are optimized for that application the class definition for FOO is compiled into the main application SWF file. If those modules were not optimized then the class definition for FOO would be compiled into the main application, ModuleA, and ModuleB SWF files.
All of this means that your modules should be optimized for your specific application, and that your application should not directly reference modules and your modules should not directly reference your application. The following is some pseudo-code that shows how to use states and modules loaders to create a modules application:
This example requires that both a ModuleA.mxml and ModuleB.mxml exist as Flex modules, which results in them getting compiled into their own SWF files. In order to interact with the application I typically create a singleton business object that maintains the current state of the application, shared data, and has the ability to change state.
For example:
[Bindable]
public class AppStateBO {
public static const STATE_A:String = "STATE_A";
public static const STATE_B:String = "STATE_B";
public var currentState:String = "";
//singleton stuff here
}
That why both the main application and each module can have access to the data they need to share and the ability to change the state of the application:
[Bindable]
var appState:AppStateBO = AppStateBO.getInstance();
...
appState.currentState = AppStateBO.STATE_A;
If the currentState attribute of the main application were bound to appState.currentState then any module with the app state singleton could change the state. There are of course many other ways to do this, but at a minimum you need something to be shared across the app and modules.

1 comment:

Nicolas said...

With Flex 4 you can reuse the same moduleloader and set the url based on the state. It's a much better way of doing it than Flex 3 used to.

you just go
url.state1='.../...swf'
url.state2='.../...swf'

When unloading you have to make sure all reference and event listeners are removed as well and it doesn't hurt to set url=null.

Thanks