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.