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.

Dear John, How do I remove Flex bindings on an object?

Question asked by Joshua.
Removing bindings requires a trick with include namespace mx_internal, which will give you access to parts of components that you would normally not have access to.
According to the source code for Binding.as (which I believe is not included in the SDK), the bindings are stored in the following places within objects:
  • mx_internal _bindings:Array
  • mx_internal _watchers:Array
  • mx_internal _bindingsByDefinitions
  • mx_internal _bindingsBeginWithWord
The following function can then be used to clear bindings on an object:

Dear John, How do I unload Flex modules?

Question asked by Joshua.
Unloading modules is a difficult thing to do, and is near to impossible in Flash Player 9. Originally this article clued my into what was going on: http://www.gskinner.com/blog/archives/2008/04/failure_to_unlo.html. Essentially to get modules to truly unload you have to get rid of all the references to them, and be using the "Copied Domain Method." The copied domain method is described here in detail, along with its effects on memory: http://jvalentino.blogspot.com/2009/06/flex-memory-issue-4-modules-and.html.
Assuming you are using the Copied Domain Method, you then have to deal with the following areas of leakage as mentioned in the originating article:
I essentially handled these area of leakages by iterating recursively through every component within a module class after unloading, removing state, removing bindings, removing common listeners, reseting the EffectManager, and then forcing garbage collection using what is called the local connection hack.
The problem with this though is that there will always be memory accumulation even if references are removed. This is due to a largely unknown and undocumented issue known as "Rendering memory fragmentation." I have discussed this issue with several engineers at Adobe through a client which I cannot name, and they are at least passively aware of it but it is an issue with the Flash Player itself. The article at http://www.craftymind.com/2008/04/09/kick-starting-the-garbage-collector-in-actionscript-3-with-air/ hinted at what was going on, which lead me into a full investigation to verify the problem.
Basically the Flash Player operates on what is called an Elastic Racetrack (http://www.onflex.org/ted/2005/07/flash-player-mental-model-elastic.php), which ends up with the memory used of AS3 object allocation and the memory used for rendering getting on the same page in memory. When the garbage collection runs the allocation space is not cleaned because the blocks contain active rendering memory and vice versa. This makes it to where the garbage collector fails to clean things, which causes leaks. Since the issue is rendering related it is more prevalent in application that are graphically intense and run at large resolutions, like kiosks. It is for these reasons that I recommend that most applications pool modules, so that the rendering and object instantiations through allocations are minimal.
In the end it will depend on how many "modules" are in your application, how big they are, and if they are really modules. It is quite common for application to incorrectly use modules because they followed the examples released by Adobe, which cause the module definitions themselves to be compiled into both the module SWF and the main application SWF. Flex operates on a compile by reference basis, so if your application has direct reference to a module class that module class gets compiled into both the module SWF and the main application SWF.