Catching UncaughtError in Flex Modules

A common issue amongst those building Flex Applications that use Flex Modules is that the UncaughtError capability of Flash Player 10.1 does not work for Modules. This is due to the fact that Modules dereference the module SWF’s loaderInfo right away, in order to make unloading modules automatic. In other words, as soon as you dereference the last instance of classes in the module, the SWF can be garbage collected. If Flex did not dereference the loaderInfo, the developer would have to keep track of what instances of module classes have been created and whether they are still around, and only if they are all gone would you dereference the loaderInfo.

It turns out that the UncaughtError mechanism relies on having loaderInfo references so the module subsystem in currently incompatible with UncaughtErrors. The Flash Player engineers are testing out a fix where the main application becomes the fallback for any UncaughtErrors that have not been caught and cancelled. For now, though, I figured out a way to hook directly to the module’s loaderInfo and listen to UncaughtErrorEvents there. That will allow you to get UncaughtErrors from the module. The key is in the timing. By the time the ModuleEvent.READY fires, it is too late, the loaderInfo has been dereferenced and is null. During ProgressEvents, the loaderInfo may not be available. But fortunately, at the time of ModuleEvent.SETUP, you can grab the loaderInfo and listen for UncaughtErrorEvents.

Here are some relevant snippets of code. Let’s say you have an application with an UncaughtErrorEvent handler like this:


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
layout="vertical"
initialize="init()">

<fx:Script>
<![CDATA[
import mx.events.ModuleEvent;

private function init():void
{
systemManager.loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR,
uncaughtErrorHandler);
}

private function uncaughtErrorHandler(event:UncaughtErrorEvent):void
{
trace("caught uncaught error");
event.preventDefault();
}

]]>
</fx:Script>

<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>

<mx:ModuleLoader id="moduleLoader" url="GEHFlexModule.swf" width="200" height="150" />
</mx:Application>

In this app, the uncaughtErrorHandler will get UncaughtErrors from every other point of the application except for the module loaded by the ModuleLoader. To get the UncaughtErrors from the module, all you have to do is add a ModuleEvent.SETUP event handler:


<mx:ModuleLoader id="moduleLoader" url="GEHFlexModule.swf" width="200" height="150" setup="setup(event)" />

and use the setup event to hook up the uncaughtErrorHandler to UncaughtErrors from the module.


private function setup(event:ModuleEvent):void
{
DisplayObject(event.module.factory).loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR,
uncaughtErrorHandler);
}

Hope that helps.

13 Responses to Catching UncaughtError in Flex Modules

  1. Thanks for an explanation, Alex, we will try this out. We are currently using a workaround that hooks to the READY event and references event.target.child.moduleFactory.loaderInfo but it’s not 100% reliable (see comments to this JIRA bug: https://bugs.adobe.com/jira/browse/FP-4978)

  2. John says:

    Hi Alex, this question is only tangentially related to your post so I apologize. When the main application loads a SWF which is another application, does the loaded SWF broadcast another application complete event to its components? I’m running into a strange behavior regarding passing values to the loaded SWF that works sometimes and not others. Thanks if you can help and I understand if you don’t on your blog.

    – JR

    • Alex Harui says:

      The loaded SWF will broadcast its own applicationComplete from the SWF’s appiication, not from the main application.

  3. Wilson Ferreira says:

    This work around did not work for me. Can i send you the project?

  4. Does that not imply that one must explicitly removeEventListener() if the module is ever to be released?

    • Alex Harui says:

      The code in the main app is listening to the subordinate loaderInfo so it should not prevent the module from unloading. Listeners set up a reference from the dispatcher back to the listener, not the other way around.

  5. Evan says:

    I seem to have inconsistent behavior from sub components within a module. I have a checkbox that on the change event calls a method like:
    private function changed(event:Event):void
    {
    if (checkBox.selected)
    {
    //do stuff
    }
    else
    {
    //do other stuff
    }
    var a:String;
    a.length;
    }

    but I never see the uncaught exception from the null pointer. However I do see the same exact error being thrown from a radio button change event. Am I doing something wrong?

  6. The solution here is for modules. There’s a similar, older, problem when using RSLs: http://bugs.adobe.com/jira/browse/SDK-28018
    (don’t let the title confuse it, it still applies to Flex 4).
    I didn’t test again with a more recent version, but I believe for that you need another workaround, like shown in my GlobalErrFlex.mxml attachment there.

    So if you’ve got a Flex 4 application using both RSL’s and modules, you’ll need two workarounds to make a global error handler work.

  7. cabaji says:

    help me a lot thnx, but in my case i load dynamically the modules using imoduleinfo
    so this was my workaround:

    modInfo = ModuleManager.getModule(widgetData.urlElement);
    modInfo.addEventListener(ModuleEvent.READY, modEventHandler);
    modInfo.addEventListener(ModuleEvent.ERROR, widgetError);
    modInfo.addEventListener(ModuleEvent.SETUP, applicationCompleteHandler);

    The important part is the setup event:

    where:

    private function applicationCompleteHandler(event:ModuleEvent):void
    {

    DisplayObject(event.module.factory).loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR,
    uncaughtErrorHandler);

    }

    private function uncaughtErrorHandler(event:UncaughtErrorEvent):void
    {
    Alert.show(“\n”
    + “\n”+ event.error.message,”Ha ocurrido un error en la aplicación”);

    // a non-Error, non-ErrorEvent type was thrown and uncaught

    }

    Yap that did it.

  8. i have one application with many modules. but in my application oncaughterror handler is not working. for example. error occurs in abc.as of another module. but i have written above code in main mxml page. so is it right way to get uncaughterro. please help me. as i am new to flex. i want suggestion from you. which steps i have to follow over here in my application. Thank you in advance.

  9. Finally I got the solution for this. anybody wants to know. just mail me at. 1057raj@gmail.com