Creating class instances from loaded applications

You can create instances in a main application of classes that are defined in a loaded sub-application. You can then add these objects to your main application and interact with them as you would interact with any other object in the display list. To access class definitions in a sub-application, you get the definitions from the sub-application’s application domain.

Each application domain contains definitions of all the classes within it. There is an applicationDomain object that you access with a reference to the loaded application’s LoaderContext. The ApplicationDomain object has two methods, hasDefinition() and getDefiniton(). The hasDefinition() method lets you detect if a class definition exists. If a class definition exists, the getDefinition() method lets you create an instance of that class in your main application.

You can’t add a UIComponent that is defined in another application domain to the main application’s display list. As a result, to create an instance of a class that is defined in another application domain, the sub-application must be loaded into a child application domain of the main application’s application domain (you cannot set the value of the SWFLoader’s loadForCompatibility property to true). The sub-application must also be in the same security domain as the main application (trustContent must be true).

You can only create the instance of the class dynamically when the class is defined in an application that is loaded at run time. This is because the compiler does not have access to classes in loaded applications at compile time, so it cannot check linkages. If the sub-application was embedded at compile time, then you would not have to create the instance dynamically, the class definition would be available to the compiler. In this case, you could instead use the new keyword with the specific class type rather than a generic Class type.

The following example main application loads a sub-application with the SWFLoader control. It sets the value of the trustContent property to true and defines a method, createClassInstance(). This method gets the definition of the custom class from its loaded application’s application domain. The example then creates an instance of this class and sets a property on it before adding it to the display list.

<?xml version="1.0" encoding="utf-8"?>
<!-- apploading/MainAppUsingSubAppDefinitions.mxml -->
<s: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">

    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout>

     <fx:Script>
          <![CDATA[
               import mx.core.UIComponent;
               public function createClassInstance():void {
                    // Check that the definition exists.
                    if (contentLoader.loaderContext.applicationDomain.hasDefinition('MyRedButton')) {
                         var objClass:Class = contentLoader.loaderContext.applicationDomain.getDefinition('MyRedButton') as Class;
                         if (objClass != null) { 
                              var newObject:UIComponent = UIComponent(new objClass());

                              // Set properties on the custom class as an associative array.
                              newObject["label"] = "Click Me";   
                              
                              // Add the new instance to the second panel in this application.
                              myPanel2.addChild(newObject);
                         }
                    }                   
               }
          ]]>
     </fx:Script>

     <!-- The SWFLoader in the first panel loads the 
           sub-application that contains a definition of MyRedButton. -->
     <mx:Panel id="myPanel" title="SubApp1 Loaded by main application">
          <mx:SWFLoader id="contentLoader" 
            trustContent="true" 
            source="SubApp1.swf"/>     
     </mx:Panel>

     <!-- This application adds an instance of the MyRedButton 
           class to the second panel after the content is loaded. -->
     <mx:Panel id="myPanel2" title="Instance of a Class Defined By SubApp1"/>
     
</s:Application>
In this case, the hasDefinition() method returns a boolean to tell if a class is present in the loaded SWF file. If it is present, the sub-application can obtain the Class using the getDefinition() method. You can then create instances by using the new keyword with the returned class.

Also notice that the createClassInstance() method is public. If it were private, the sub-application would not be able to call it.

The sub-application, SubApp1.swf, statically links a custom class called MyRedButton. It also calls the parent application’s method when it is done. You cannot call that method in the parent application’s applicationComplete event, because that event will likely be triggered too early in the initialization process. Wait for the sub-application to complete its loading and initialization before you create an instance of a class that is defined in it.

<?xml version="1.0" encoding="utf-8"?>
<!-- apploading/SubApp1.mxml -->
<s: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"
    xmlns:custom="*"
    creationComplete="initApp()" 
    applicationComplete="mx.core.FlexGlobals.topLevelApplication.createClassInstance()">

    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout>
    
     <fx:Script>
          <![CDATA[
               private function initApp():void {
                    var child:DisplayObject = getChildAt(0);
                    var childClassName:String = getQualifiedClassName(child);
                    
                    // Show that the qualified class name of the custom button is MyRedButton.
                    trace(childClassName);
               }
          ]]>
     </fx:Script>

     <custom:MyRedButton id="myRedButtonId" label="Click Me"/>

</s:Application>
The MyRedButton class is a simple MXML component that extends Button and defines its color as red. The following example shows this custom class:
<?xml version="1.0" encoding="utf-8"?>
<!-- apploading/MyRedButton.mxml -->
<s:Button
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx"
    color="red">
</s:Button>