Loading Flex Applications Into Flex Applications Gotcha: App Resizing

I should be asleep, but this is such an awesome bug. Have the need to load one Flex app into another Flex app at work. Modules force us to refactor our 2 separate code bases, which we don’t have time nor budget to do right now and a component suffers from the same problem. Using a unique ApplicationDomain, I can load an app Mike built into an app I built without worrying about class collisions.

Nick, a co-worker and brilliant PHP developer not even out of college, found a bug where if you went to a state that showed Mike’s app, then left that state which removes Mike’s app from the display list (that’s how states work), and then resized the browser, you got an exception. The stack trace is just 1 line, basically stating that mx.managers.SystemManager is having a problem with a null object in the Stage_resizeHandler function.

The short description of the problem is that the “stage” property of DisplayObjects is null when a DisplayObject is not in the DisplayList. It’s set after it’s added. The SystemManager is designed to assume that the stage is never null in this case. The stage does become null, though, because since this application is only shown in one state, and then not shown in another means that it’s removed from the DisplayList. Therefore, the listener to the Stage object is still there, and the resize handler gets triggered when you resize your browser. Since the whole entire app, SystemManager included, is in fact a DisplayObject, it fails since its stage object is now null.

It’s a justified design decision because the use case of loading Flex apps into other Flex apps is just weird to begin with, and thus an edge use case that doesn’t really get much testing. The “right” thing to do would be to build an encapsulated component or Module, thus rendering this use case invalid, and thus not a problem.

The solution for now isn’t pretty because SystemManager’s resize handler, and the rest of the code it uses to setup the stage listeners is private, thus nothing I can really do save modifying the code directly, and recompiling the SWC. Not really a solution.

Instead, we just removed the external app from the state, and add it to the main app. We then just use a SetProperty action for the state tag to toggle the visibility. Since being invisible and being out of the DisplayList are 2 different things, with the former still retaining a non-null reference to the Stage via the stage property, it works. To say that another way, when you set the visibility of a DisplayObject to false, like a MovieClip, it still retains it’s reference to the stage.

Interestingly, I reckon removedFromStage was added in a new Flash Player 9 build (don’t know which one) because the 2.01 docs show it for flash.display.DisplayObject whereas the 2.0 docs do not. If SystemManager were to respond to this event, I think things would work just fine. Either that, or just code things to assume stage may be null.

…again, in all fairness, this is a problem Flash Developers have run into for years, so didn’t really think it’d go away in Flex (although, I hoped it would). To quote one of the Flash greats with regards on how to code your Flash apps, which could apply in this case to your Flex apps:

Be prepared to be loadMovie’d!

3 Replies to “Loading Flex Applications Into Flex Applications Gotcha: App Resizing”

  1. Hi Jesse

    We had a similar issue where we had to load 1 Flex app into another with a similar codebase. We went the route of loading the 2nd app via SWFLoader (fortunately the 2nd codebase was so small that we could get around the similar codebase issue by changing its package structure without too much bloat in the runtime code)

    Everything has been running smoothly, but I checked for the bug u described this morning and whooa – it broke. With our app we add & remove it to a DisplayObject on the stage to control its visibility. Our 2nd app doesnt make too much use of the stage object, so again I could get away with a simple quickfix by just checking whether the stage is null.

    Thanks for the tip off, very useful :)

  2. I really think there are three options, and using SWFLoader isn’t one of them, as we found out. One is to use modules. Another is to make the child app a library project or SWC, and create mxml components inside the original app that consume data from the SWC. The last solution is to merge the business logic between the two apps. I like the latter of course, since there’s more separation of business logic from presentation. However there’s still the problem of two apps using the same version of Cairngorm. Now that 2.2 is a fraction of the size of 2.1, that’s not a show-stopper. But why should two separate apps compile with their own Cairngorm? Now we get into the architecture more hard-core, and it becomes apparent that a central SWC for business logic is needed for the two apps to play nicely. So…the SWC being used to return your service calls should have hooks for my service calls. That way I can elegantly blend in my code with yours, and we all win, in theory, because there’s a central API for all of it. This may be the direction we should go.

    Thoughts?

Comments are closed.