Futurescale, Inc. PureMVC Home

The PureMVC Framework Code at the Speed of Thought


Over 10 years of community discussion and knowledge are maintained here as a read-only archive.

New discussions should be taken up in issues on the appropriate projects at https://github.com/PureMVC

Pages: [1]
Print
Author Topic: Flash CSS/AS3 example of loading external swf as module under MultiCore - Help  (Read 19629 times)
rhart
Newbie
*
Posts: 3


View Profile Email
« on: August 15, 2008, 11:19:09 »

Hi Cliff and other fellow PureMVC developers.

I have been using the Standard version of PureMVC under Flash CS3, and I've been very happy with the results.

I am really excited to make the jump to Multicore for Flash CS3, but since there are no examples, I thought I'd have a go at doing one up. In particular, I wanted to know how to take external standalone swf files (they may use the PureMVC Multicore framework or not) and be able to load one of these into a "Shell" app. My understanding was that Multicore allows for multiple instance of the PureMVC Framework to run under one shell in 1 VM, and that there is no need to bump these externally loaded apps into a separate ApplicationDomains, since multiple instances of the framework are permitted under MultiCore, which was not the case with the old Standard edition as far as I understand.

I did up a very simple SHELL that initializes with it's own key, and then I did up a simple module(external SWF if you CS3 guy/gall), which also initializes with a different key. The main app fires up, and has a button you can click that tries to load the module(external PureMVC enabled swf).

What I was expecting was for the App/Shell to load in the external swf(module) and display it, and because it has it's own key, it carries on with its startup routine, independent of the main app/shell.

What I am finding is that the app/shell tries to load in the module/swf file, but then for some reason, instead of the module running it's own starup routine, it causes the main app/shell to rerun it's startup routine. As far as I am aware, this should not happen, since both shell and module were created with different keys. It's like the module is having an identity crisis or something.

Also, When I try loading in a module/external swf with no PureMVC code in it, it loads into the shell no problem and displays as expected.

I have uploaded both the shell and the module code for people to have a look at. If anyone has as any ideas what is going on, or what I'm missing, I'd really appreciate the help. Once I have this working, I'd like to get it working with pipes, spiffy it up and submit if for an example since there are none currently for Flash CS3.

Files:
http://www.ethicalentertainment.net/AS3_Multicore_Modules_Example.zip

Also, if your curious I'm using Anthropod to view my trace/debugs. I've found it really useful for Flash and Air projects.
http://arthropod.stopp.se/

Cheers,

Richard




Logged
rhart
Newbie
*
Posts: 3


View Profile Email
« Reply #1 on: August 16, 2008, 04:15:04 »

Just to give a little more detail...

Here is my document class for my shell:

:
package
{
import com.ethicalentertainment.monkeyshell.ApplicationFacade;
import flash.display.Sprite;
import com.carlcalderon.arthropod.Debug;

public class Main extends Sprite
{
private var facade:ApplicationFacade;
public static const NAME:String = 'Shell'; //Main Application/Core ID/NAME

public function Main()
{
Debug.log("Step 1 - SHELL Creating Instarce of Facade");
facade = ApplicationFacade.getInstance(NAME); //mulicore way

Debug.log("Step 2 - SHELL calling Facades startup");
facade.startup( this.stage );
}
}
}

And Here is the document class for my external "swf/cs3 module":


:
package
{
import com.ethicalentertainment.monkeymodule.ApplicationFacade;

import flash.display.Sprite;

import com.carlcalderon.arthropod.Debug;

public class Main extends Sprite
{
private var facade:ApplicationFacade;

//Main Application/Core ID/NAME
public static const NAME:String = 'Module';

public function Main()
{
Debug.log("Step 1 - MODULE creating new Instarce of Facade");
facade = ApplicationFacade.getInstance(NAME); //mulicore way

Debug.log("Step 2 - MODULE calling Facades startup");
facade.startup( this.stage );

}
}
}

Here is my Shell ApplicationFacade:

:
package com.ethicalentertainment.monkeyshell
{
    import org.puremvc.as3.multicore.interfaces.IFacade;
    import org.puremvc.as3.multicore.patterns.facade.Facade;
    import com.ethicalentertainment.monkeyshell.controller.StartupCommand;
import com.carlcalderon.arthropod.Debug;
   
    public class ApplicationFacade extends Facade implements IFacade
    {
        // Notification name constants
        public static const STARTUP:String  = "startup";
        public static const INITIALIZE_ENGINE:String  = "initializeEngine";
        public static const SECTION_CHANGED:String  = "sectionChanged";
public static const VIEW_SCREEN_START:String  = "viewScreenStart";

//////////////////////////////////////////////////////////////
//Constructor of ApplicationFacade
public function ApplicationFacade( key:String )
{
super(key);
}
//////////////////////////////////////////////////////////////
public static function getInstance( key:String ) : ApplicationFacade
        {
Debug.log("getInstance being called on Facade");
            if ( instanceMap[ key ] == null ) instanceMap[ key ] = new ApplicationFacade( key );
            return instanceMap[ key ] as ApplicationFacade;
        }
/////////////////////////////////////////////////////////////
        override protected function initializeController() : void
        {
            super.initializeController();
            registerCommand( STARTUP, StartupCommand ); //can choose to map a notification to a command if you want, but not requried
        }
        //////////////////////////////////////////////////////////////
        public function startup( stage:Object ):void
        {
        Debug.log("Step 3 - AppicationFacade sending notification to startup, which triggers startup command");
        sendNotification( STARTUP, stage );
        }
        //////////////////////////////////////////////////////////////
    }
}

And here is the Facade for my external swf/module:

:
package com.ethicalentertainment.monkeymodule
{
    import org.puremvc.as3.multicore.interfaces.IFacade;
    import org.puremvc.as3.multicore.patterns.facade.Facade;
    import com.ethicalentertainment.monkeymodule.controller.StartupCommand;

import com.carlcalderon.arthropod.Debug;
   
    public class ApplicationFacade extends Facade implements IFacade
    {
        // Notification name constants
        public static const STARTUP:String  = "startup";
        public static const INITIALIZE_ENGINE:String  = "initializeEngine";
        public static const SECTION_CHANGED:String  = "sectionChanged";

public static const VIEW_SCREEN_START:String  = "viewScreenStart";


//////////////////////////////////////////////////////////////
//Constructor of ApplicationFacade
public function ApplicationFacade( key:String )
{
super(key);
}
//////////////////////////////////////////////////////////////
public static function getInstance( key:String ) : ApplicationFacade
        {
Debug.log("getInstance being called on Facade");
            if ( instanceMap[ key ] == null ) instanceMap[ key ] = new ApplicationFacade( key );
            return instanceMap[ key ] as ApplicationFacade;
        }
/////////////////////////////////////////////////////////////
        override protected function initializeController() : void
        {
            super.initializeController();
            registerCommand( STARTUP, StartupCommand ); //can choose to map a notification to a command if you want, but not requried
        }
        //////////////////////////////////////////////////////////////
        public function startup( stage:Object ):void
        {
        Debug.log("Step 3 - AppicationFacade sending notification to startup, which triggers startup command");
        sendNotification( STARTUP, stage ); //send out a startup notification that will initiated teh StartupCommand
        }
        //////////////////////////////////////////////////////////////
    }
}

I believe the error message I was getting was something like "can't reference null object" when the shell tries to load in the module.

I have all the other code for for my facades and mediator and proxies in the zip file for both the shell and the zip.

Could it be a problem with both the Shell and the external SWF trying to reference the stage? Or maybe a timing issue (ie something hasn't initialized in time?)

Since we are dealing with multicore, I did move things that used to be in the contructor to the onRegister, so I  don't think that the problem.

Is there something different that needs to happen with my external SWF/module to make it load in properly under Flash CS3/PureMVC multicore?

Really appreciate some thoughts or ideas in if what I'm trying to do is possible in Flash CS3/PureMVC multicore and if so, what I seem to be missing.

Cheers,

Richard



Logged
danielcsgomes
Full Member
***
Posts: 47

 - daniel@onedesign.com.pt
View Profile Email
« Reply #2 on: August 17, 2008, 04:06:14 »

Hi rhart,

I can't help you much (i am a newbie) but i can tell you that error "can't reference null object" you are getting maybe is because you are trying to communicate with an object/component that is not instance in the application and you dont have any reference to him, i am getting this error too  :-\

Daniel Gomes
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #3 on: August 17, 2008, 04:47:56 »

Sounds like load timing to me, but then this is a lot of code to debug.does this debugger of yours let you know if you're inside the module when you get the error?

-=Cliff>
Logged
rhart
Newbie
*
Posts: 3


View Profile Email
« Reply #4 on: August 18, 2008, 09:38:38 »

Just about have the problem licked!

Turns out, that the problem was due to the Document class of the main shell/app and the document class of the loading module having the same name. (ie both were called Main.as). When the module/external swf tried to load in, the Main.as class of the shell was overriding or superseding that of the Main.as of the module, and hence the weird identity crisis. In effect the Main.as of the shell was reinitializing and rerunning its start up routine.

To solve the problem, I went in and named my document class for my module/external swf to Module.as, or something different than whatever you named the document class for your main app/shell.  The module is now loading in and displaying and running its own PureMVC startup routine.

Thanks for the ideas and help.

I'm going to try and clean up the example and try and add pipes next. If all goes well I will post the example up for others to have a look at with all the code.

Cheers,

Richard
Logged
Bill_BSB
Jr. Member
**
Posts: 13


View Profile Email
« Reply #5 on: September 04, 2008, 06:03:02 »

Hello guys,

I´m stuck with loading external SWF files. I´m building a modular app in Flex using PureMVC MultiCore-Pipes(PMVCMCP). The main idea is to have several stand alone applications that are all PMVCMCP that are loaded in a big Shell app that coordinate them all. I have all my modules built, each one in a Flex project with different output folders.

The problem is in the Shell. I´ve tried loading the external SWFs in two different ways: using the techinique used by Jens (http://www.websector.de/blog/2008/06/21/a-basic-puremvc-multicore-as3-example-using-pipes-utility-and-modules/) but it doesn´t work because it needs a reference to the Module Class and my app are completly unknow/unaware of each other.
So I tried using Joshua´s (http://www.joshuaostrom.com/2008/06/17/pipe-demo-mortgage-app/) techinique but he uses his own PureMVCModules lib that is way too "powerfull" for my current needs. I found the source of the lib here http://www.joshuaostrom.com/2008/05/24/as3-puremvc-dynamic-modules/.
Then I tried some Adobe techiniques (http://livedocs.adobe.com/flex/3/html/help.html?content=modular_3.html) but got NO donut.  :-\

When I use the techiniques described above, the SWF is loaded by the ModuleManager but it never dispatch the ModeEvent.READY event. I´ve tried some hacking but it didn´t work since my hacking skills are just l4m3.

I also tried this tech (http://livedocs.adobe.com/flex/3/html/help.html?content=Working_with_MovieClips_7.html) from Adobe but I get Error #1034: Type Coercion failed: cannot convert flash.display::Loader@756bec1 to mx.core.IUIComponent.

So I´m stuck. I need help real bad! I just don´t know what to try now! And I really, really don´t want to merge all my apps/modules in one single Flex Project. They all have to be stand alone apps.

Thanks
Logged
Bill_BSB
Jr. Member
**
Posts: 13


View Profile Email
« Reply #6 on: September 04, 2008, 01:18:31 »

AHA! I finally made it! I´ll just put the code of my solution here so anyone can have a look.

Foo class:
:
package
{
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLRequest;
import flash.system.System;

import mx.core.UIComponent;
import mx.managers.CursorManager;
import mx.rpc.events.FaultEvent;

// Foo is a UIComponent. It´s responsible for loading the modules and stuff.
//I did this because I was getting an Error saying that Loaded isn´t a IUIComponent.
public class Foo extends UIComponent
{
private var _request:URLRequest;
private var _loader:Loader;
private var _loaded:Boolean;
private var _url:String;

public function Foo(url:String)
{
super();
_url = url;
_request = new URLRequest(url);
_loader = new Loader();

_loaded = false;
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaded);
_loader.contentLoaderInfo.addEventListener(FaultEvent.FAULT, onFault);
}

// Try to load the Module from the URL passed on the constructor
public function loadIt():void{
CursorManager.setBusyCursor();
try{
_loader.load(_request);
}
catch (error:Error)
            {
            CursorManager.removeBusyCursor();
                trace("Unable to load URL: " + error);
            }
}

// Try to clear everything.
public function unlonadIt():void{
removeChild(_loader);

_loader.unload();

_loader = null;

_loaded = false;

// Try to GC again.
flash.system.System.gc();

dispatchEvent(new Event("REMOVED",true));
}

//
private function onLoaded(evt:Event):void{
//trace(_url+" load success");
CursorManager.removeBusyCursor();

_loaded = true;

// Loader can be added to the UIComponent class. ???
addChild(_loader);

// Inform everything went just fine.
dispatchEvent(new Event("OK",true));
}

// Inform something went wrong
private function onFault(evt:FaultEvent):void{
//trace(_url+" load FAIL");
_loaded = false;
dispatchEvent(new Event("ERROR",true));
}

public function get loaded():Boolean{
return _loaded;
}
}
}

SimpleShell.mxml
:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">

<mx:Script>
<![CDATA[
import mx.rpc.events.FaultEvent;

// Flag to control module loading
private var _hasModule:Boolean = false;

// My module manager class
private var _foo : Foo;

// The previous value of memory avaiable from System.totalMemory
private var _pmem:Number = 0;

// Local path to your SWF. Change all '\' to '/'.
private static const MAP_MODULE_URL:String =
"C:/mymodules/ModuleA.swf";

private static const CAPTIONATOR_MODULE_URL:String =
"C:/mymodules/ModuleB.swf";

// Add listeners for events dispatched by Foo class.   
private function init():void{
this.addEventListener("OK", onComplete);
this.addEventListener("ERROR", onFault);
this.addEventListener("REMOVED", onComplete);

// Initializate the memory indicator before loading modules
_pmem = System.totalMemory;

// Divided by 1024 to simplify viewing
lblMemory.text = "Total Memory: "+String(_pmem/1024);
}

private function onComplete(evt:Event):void{
// the current total memory value after module loading
var mem:Number = System.totalMemory;
lblDelta.text = "Diff: "+String((_pmem - mem)/1024);
lblMemory.text = "Total Memory: "+String(mem/1024);

// now previous value is the current one
_pmem = mem;

// Parse the event sent by Foo.
if(evt.type == "OK")
_hasModule = true;
else if(evt.type == "REMOVED")
_hasModule = false;
}

private function onFault(evt:Event):void{
_hasModule = false;
}

// Try to invocate the Garbage Collector. Not sure if it will in fact collect.
private function garbage():void{
var mem:Number = System.totalMemory;
flash.system.System.gc();
lblMemory.text = "Total Memory: "+String(mem/1024);
lblDelta.text = "Diff: "+String((_pmem - mem)/1024);
_pmem = mem;
}

// Invoked everytime the load button is clicked.
private function loadModule():void{

// Change buttons behavior
if(_hasModule == false){

btnLoad.label = "Unload";

// Load module selected in the Combo Box
if(cbxModules.selectedIndex == 0) {
_foo = new Foo(MAP_MODULE_URL);
_foo.loadIt();
}
else {
_foo = new Foo(CAPTIONATOR_MODULE_URL);
_foo.loadIt();
}

// Add the Foo class to the UIComponent. Foo´s also an UIComponent.
module.addChild(_foo);
}
else{
// Clear things up...
btnLoad.label = "Load";
_foo.unlonadIt();
module.removeChild(_foo);
_foo = null;

// ...and try to free memory
garbage();
}
}
]]>
</mx:Script>

<mx:VBox width="100%">
<mx:ApplicationControlBar x="10" y="10" width="100%">
<mx:ComboBox id="cbxModules" dataProvider="{['Module A', 'Module B']}"/>
<mx:Button label="Load" id="btnLoad" click="loadModule()"/>
<mx:Button label="GarbageCollection" id="btnGarbage" click="garbage()"/>
<mx:Label id="lblMemory" text="" width="100%"/>
<mx:Label id="lblDelta" text="" width="100%"/>
</mx:ApplicationControlBar>
<mx:UIComponent id="module" width="100%" height="100%"/>
</mx:VBox>
</mx:Application>


I used the Loader class to load my external SWFs and it worked. Now it´s pumbling time!
 ;D
Logged
Pages: [1]
Print