Flex Modules Watch Your Scope

Here’s another help hint for those working with Modules in Flex: Watch your variable scope!!

When loading modules, you have a number of options for loading the SWF including the ModuleLoader and ModuleManager. If neither of those fit your needs you always have access to Flash’s Loader class. ModuleManger can be used for fine grained control of the loading process. Either way, variable scope plays a crucial roll in the loading process.

Here’s an example using ModuleLoader…

public function loadSWFModule(swfURL:String):void
{
var moduleLoader:ModuleLoader = new ModuleLoader();
moduleLoader.url = swfURL;

moduleLoader.addEventListener(ModuleEvent.READY,onModuleLoaded);
moduleLoader.addEventListener(ModuleEvent.ERROR,onModuleError);
moduleLoader.addEventListener(ModuleEvent.PROGRESS,onProgress);
moduleLoader.loadModule();
}

The moduleLoader is declared as a local variable. As it turns out this will cause problems, even with the ‘strong’ event listeners. For those not wanting to read the technical details to follow, simply use avoid using a locally scoped variable.

The following are some of the symptoms you may run into using the latter locally scoped variable:

To help those searching the net, I’ll be a bit redundant in the ‘symptom’ descriptions so hopefully you’ll find this post if you’ve stumbled upon this problem

Symptons

  • The module fails to load the first time, but loads successfully the second time.
  • The ModuleEvent.READY is never dispatched
  • The ModuleInfoProxy never picks up the ModuleEvent.READY dispatched by ModuleInfo
  • ModuleInfo.clearLoader() throws an error (which is quietly caught), Error #2029: This URLStream object does not have a stream opened when calling loader.close()
  • The problem comes in when the Loader finishes loading the SWF. ModuleInfo’s internal listener list (listeners attached during ModuleInfoProxy’s constructor) are lost (i.e. null) when ModuleInfo finally reaches it’s readyHandler( ) method. At the end of the readyHandler( ), a ModuleEvent.READY event is dispatched.

    dispatchEvent(new ModuleEvent(ModuleEvent.READY));

    With the listener list being null, the event is never picked up by the ModuleInfoProxy and the initial load fails.

    On subsequent loads (i.e. the second time) ModuleInfoProxy’s load( ) method checks to see if the info has already been loaded and dispatches the ModuleEvent.READY event directly.

    else if (info.loaded)
    {
    //trace("Module[", url, "] load is already loaded");
    if (info.setup)
    {
    ...
    if (info.ready)
    {
    ...
    dispatchEvent(new ModuleEvent(ModuleEvent.READY));
    }
    }
    }

    Causing the load to ‘work’ the second time.

    My understanding is that Garbage Collection is often invoked when a module is loaded. It looks like it’s the cause of this behavior (the listeners being lost). I assumed that the ‘strong’ listeners would be enough to keep the GC away, oh well.

    Again the solution is simple, make sure your not using a locally scoped variable when loading modules.

    13 Replies to “Flex Modules Watch Your Scope”

    1. hi, thanks for your post Joshua.

      for some reason i have to load many modules in the same time, and each instance need to initiate in the local variable scope.

      And it seems it still works if I put the new instance of ModuleLoader into a Local array variable

      Code as following:

      private var loaderArr:Array = new Array();

      public function LoadModuleFromSWF(path:String) : void
      {
      var loader:ModuleLoader;
      loader = new ModuleLoader();
      loader.url = path;
      loader.addEventListener(ModuleEvent.READY, onModuleLoaded);
      loader.addEventListener(ModuleEvent.ERROR, onModuleError);
      loader.addEventListener(ModuleEvent.SETUP, onSetup);
      loader.addEventListener(ModuleEvent.UNLOAD, onUnload);
      loaderArr.push(loader);
      loader.loadModule();
      }

    2. Incedentaly, we came across this in windows, but not Linux, so there is probably some difference in the garbage collection between the two flash players.

      Thanks for the post though, it did solve our problem.

    3. i couldnt be able to load the module for the first time using moduleloader.
      but its getting loaded for the second time. as per ur article i also tried not using locally scoped variable.even then listener is not dispatched for the first time. its trigerred for the second call.
      plz send me a sample code snippet asap.. its seems to be a major issue. plz help me out to solve this problem.

    4. Nithya,
      Try using module manager has you’ll have a finer grain of feedback / control. Loading modules will usually launch the garbage collector so watch your scope.

    5. Oh, thank you so much for posting this. For the life of me I could not figure out why ModuleEvent.READY was not being dispatched when loading on startup.

      This behavior is quite bizarre – Adobe really should document this better.

      At any rate, you and Google are my best friends. đŸ™‚

    6. Having the same issue, however my ModuleLoader’s are on the stage, not instantiated from code. Any solutions for that scenario?

    7. Hi ,

      I cannot assgn a module loader to local variable

      private function assgnLoader():void{

      var loader:ModuleLoader = ml;

      }

      This throws TypeError.

      what is the problem it could be ..

      Please help

      i tried the follwing too .

      var loader:ModuleLoader = ModuleLoader (ml);

      and

      var loader:ModuleLoader = ml as ModuleLoader;

      leads the same error.

      Please help

    8. Hi ,

      I cannot assgn a module loader to local variable

      private function assgnLoader():void{

      var loader:ModuleLoader = ml;

      }

      This throws TypeError.

      what is the problem it could be ..

      Please help

      i tried the follwing too .

      var loader:ModuleLoader = ModuleLoader (ml);

      and

      var loader:ModuleLoader = ml as ModuleLoader;

      leads the same error.

      Please help

    9. @Naju Have you see the code above where Joshua wrote like this :

      Here’s an example using ModuleLoader…

      public function loadSWFModule(swfURL:String):void
      {
      var moduleLoader:ModuleLoader = new ModuleLoader();
      moduleLoader.url = swfURL;

      moduleLoader.addEventListener(ModuleEvent.READY,onModuleLoaded);
      moduleLoader.addEventListener(ModuleEvent.ERROR,onModuleError);
      moduleLoader.addEventListener(ModuleEvent.PROGRESS,onProgress);
      moduleLoader.loadModule();
      }

      Hope it helps.. ^_^

    10. I was “this close…”!!! [shooting myself in the head] – as always – you’re so much smarter than google!!! :)) I didn’t try this yet, but I am sure it must work!!! Thank a lot!

    11. For me it happend… i followed your instructions by putting the moduleLoader as global.. but the same problem occurs..but i fixed it differently…

      The object where this module loading logic is going on is called from a local instance in the main application. So, GC is clearig it off in the main application..local variables.. it was a shock to me.. so, if the same problem is occuring to you.. check to see where you are calling this logic from..

    Leave a Reply

    Your email address will not be published. Required fields are marked *