Today I was working with a baffling bug in the Flex Bug Base. It was titled “SWFLoader loading the same app twice, which contains Button which pops up alert will throw RTE when clicked on the second button” and you can see it here SDK-11910
I did a whole lot of debugging and finally needed help from Nisheet… to get to the bottom of the issue. The issue is as follows…
You have multiple apps loaded into a main app using a SWFLoader. Now each of the apps loaded use one of the singletons used in the framework (in the case of the bug, it was the PopUpManager, as the person was using an Alert in the sub App). When he tries to use the methods of the Singleton (in this case thru the Alert.show() method in each of the sub apps), it works for only the first sub app and all others generate the following RTE (Run Time Error) for the others
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at mx.managers::PopUpManager$/addPopUp()
at mx.controls::Alert$/show()
In his case, each of the sub app had the following code (Sample.mxml)…
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” layout=”absolute”>
<mx:Button label=”Click me” click=”mx.controls.Alert.show(‘Button selected!’);”/>
</mx:Application>
And his main app was as follows (main.mxml)…
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml”>
<mx:SWFLoader id=”swfloader” source=”Sample.swf”/>
<mx:SWFLoader id=”swfloader2″ source=”Sample.swf”/>
</mx:Application>
The following execution map resulted in the RTE
- The main app starts and loads the sub apps
- When the user clicks the button in the first sub app, the SWFLoader asks its parent if it has an instance of the IPopUpManager interface.
- Since the main app has not created or cached its IPopUpManager, it replies negative and the sub app goes ahead and creates one for itself and pop’s the Alert
- Now when the user clicks the button in the second subapp, it again repeats Step 2 & Step3
- But in Step3, it encounters a code in the framework (in PopUpManager.as)
- private static var impl:IPopUpManager = Singleton
.getInstance(“mx.managers::IPopUpManager”) as IPopUpManager; - This casting using the as operator fails and thus generates the RTE.
The solution for this is to initialize the main app such that it creates and caches its own IPopUpManager interface, so that both sub-Apps can use the same, without any conflict. The altered main.mxml would look like this
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” initialize=”initApp()”>
<mx:Script>
<![CDATA[
import mx.managers.IPopUpManager;private function initApp():void{
IPopUpManager;
}
]]>
</mx:Script>
<mx:SWFLoader id=”swfloader” source=”Sample.swf”/>
<mx:SWFLoader id=”swfloader2″ source=”Sample.swf”/>
</mx:Application>
This solves the issue. Please Note that this same step has to be taken, also when your sub apps share other managers like CursorManager, HistoryManager…etc.