Sharing code between swfs - apache-flex

Lets say I have two swfs A and B, and at runtime, swf A loads swf B, and I wish to share code between them, to minimize file size and download times.
If swf B has some code (say. com.blah.HelloWorld), I tell the compiler to have swf B's source in swf A's classpath, but only do a compile-time link and not actually compile com.blah.HelloWorld into swf A.
This works, and I have tried it, using a the -includes and -externs compiler options.
However, My problem is that I wish to do this the other way. i.e. swf A and B (and potentially swf C) all need com.blah.HelloWorld, but I want com.blah.HelloWorld to be compiled into just swf A, have it as an external reference in swf B ( and potentially C as well.)
I tried doing this using the externs and includes, but I get ReferenceErrors when I do this.
I want to do this without a having a separate rsl, so I can reduce the number of http requests.
Is this possible?

You can split your flex application into modules.
Or you can access individual classes from an SWF loaded at runtime using the getDefinition method of the ApplicationDomain class:
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoad);
loader.load(new URLRequest("c.swf"));
//..
private function onLoad(e:Event):void
{
var domain:ApplicationDomain = LoaderInfo(e.target).applicationDomain;
var Type:Class = domain.getDefinition("pack.MyComponent") as Class;
var myBox:Sprite = new Type();
addChild(myBox);
}

I'm not sure I'm quite understanding your question, but I think you can use the AS3 Loader class to do what you want. The format would be something like this - let's say we're creating your main app (which will be called "a.swf") and you want to access methods and properties that have been compiled into another app (called "b.swf"), you'd do this:
var SWFB:Object; // empty at first as a placeholder.
var url:URLRequest = new URLRequest("b.swf");
var l:Loader = new Loader();
l.contentLoaderInfo.addEventListener(Event.COMPLETE, loaded);
l.load(url);
function loaded(e:Event):void {
SWFB = e.currentTarget.content as Object;
initApp();
}
function initApp():void {
SWFB.someMethodCall();
}
... and I THINK that'll work. I can't test it right now, but try it and let me know. Basically you're going to be loading b.swf in as a basic object, and you can then call methods against that object.
Please let me know if that worked, and if not I can refine it for you tomorrow.

I'm not sure if this is exactly what you want, but you could use some javascript to allow the two swfs to work together.
Here is a tutorial:
http://greeneggsandcam.com/tutorials/connect-2-swfs

Related

AS3 variables handling by AVM/compiler/scope

I have couple of questions about AS3 variables handling by AVM/compiler/scope
.1. This code in Flash will throw an error:
function myFunction() {
var mc:MovieClip=new MovieClip();
var mc:MovieClip=new MovieClip();
}
but it won`t throw an error in Flex (only warning in Editor). Why?
.2. How Flash sees variables in loops? Apparently this:
for (var i:int=0; i<2; i++) {
var mc:MovieClip=new MovieClip();
}
isn`t equal to just: var mc:MovieClip=new MovieClip();
var mc:MovieClip=new MovieClip(); because it will throw an error again as earlier in Flash, but in Flex in function not? Is Flash changing somehow my loop before compilation?
.3. Where in a class in equivalent to timeline in Flash - where in class I would put code which I put normally on timeline (I assume it is not constructor because of what I have written earlier, or maybe it`s a matter of Flash/Flex compiler)?
#fenomas thanks for explaining, but I checked 1. answer and it is not enitirely true :) this code: function myFunction() {
var mc:MovieClip=new MovieClip();
mc.graphics.beginFill(0x0000FF);
mc.graphics.drawRect(0,0,100,100);
mc.graphics.endFill();
addChild(mc);
var mc:MovieClip=new MovieClip();
mc.graphics.beginFill(0x000000);
mc.graphics.drawRect(0,0,30,30);
mc.graphics.endFill();
addChild(mc);
}
myFunction();
will compile in Flash in strict mode but with warning mode turned off and won`t throw an error during compile or runtime.
And it will also compile and execute nicely in Flex (event with -strict -warnings compiler commands) (checked with Flash CS3 and FlashBuilder 4).
The same code, but not wrapped in function will generate compile time error regardless off any error modes turned on (strict/warning)in Flash.
Is that what #back2dos said about Flash Compiler that behaves weirdly?
What is the differences between these two compilers Flash/Flex (why I have to change errors mode in Flash while Flex does not care about anything:) )?
Well, I will explain to you, how package level ActionScript (classes and global functions) is scoping.
The var statement declares a variable within the scope of the function body it is in. It's visibility is within the whole body. thus the following is completely valid.
a = 3;
if (Math.random()>0.5) {
var a:int = 0;
}
else {
a = 6;
}
this is horrible, but it's based on the abandonend ECMA-Script draft AS3 is based on ... yay! :(
for simplicity, imagine that all variable declarations are actually at the start of the containing function body (while their initialisation is actually performed in the place where you put it)
thus
for (var i:int=0; i<2; i++) {
var mc:MovieClip=new MovieClip();
}
is equal to
var i:int, mc:MovieClip;
for (i=0; i<2; i++) {
mc=new MovieClip();
}
the first piece of code from your first question to a duplicate variable defininition, which causes a compiler warning, but works as if you had made only one declaration.
as for your third question: there is no equivalent at all.
AS3 in the flash IDE and many designer friendly concepts (such as frames) are highly ambiguous. from a developer's point of view the flash IDE is about the worst piece of cr*p you can get for money (which stop it from being a great tool for design, drawing and animation). if you want clear and consistent behaviour, I advise you not to use the flash IDE for compiling ActionScript or to waste time on trying to find out why it behaves so weirdly. Apart from its quirks, it takes a long time to compile and the strange things it does to your ActionScript (such as converting local variable declaration to instance field declaration (which is probably the source of your problem)).
These are great questions. In order:
By default, Flash Authoring FLAs start in strict mode. You can change it in File > Publish Settings > AS3 settings. However, duplicate variable definitions are not a runtime error, just something that the authoring environment may or may not throw a warning or error about, depending on configuration and whether it's a class or frame script.
Incidentally, when comparing Flash and Flex make sure that your Flash scripts are inside a class, since frame scripts are a subtle different animal (as discussed below).
AS3 does not have block-level scope, so it implements a practice called "hoisting", where the compiler moves all declarations (but not assignments) to the beginning of the function in which they occur. Hence, even though your var statement is inside a loop, declaration occurs only once when the function begins to execute. See here for more details.
Frame scripts are a bit anomalous. They're sort of like anonymous functions, except that all scripts on a given timeline are considered to be in the same lexical scope. So if you use a var statement to create a local variable in one frame script, the variable will still exist when you execute a different frame script of the same object.
This is basically for historical reasons, but the result is essentially the same as having all your frame scripts in one big function and jumping around with GOTOs. Hence you should always keep all your real code in classes, and use frame scripts only to call class methods that you need to be synchronized with timeline animations. This not only lets you avoid needing to understand precisely how frame scripts differ from class code, it's good coding practice for a couple of reasons unrelated to the stuff we're talking about here.

Use StyleManager.setStyleDeclaration to set button skins in Flex

I am trying to load an swf file which has button skins as images (In the library of the swf file i have given export properties which is 'TickMark') and set the skin of a flex button using StyleManager.setStyleDeclaration.
I am getting errors like 'Argument count mismatch on TickMark(). Expected 2, got 0.'
This is what i am trying to do:
private function init():void
{
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,styleSWFLoaded);
loader.load(new URLRequest("styles.swf"),new LoaderContext(false,ApplicationDomain.currentDomain));
}
private function createStyle(styleName:String):void
{
var style:CSSStyleDeclaration = new CSSStyleDeclaration(styleName);
var cls:Class = ApplicationDomain.currentDomain.getDefinition(ss) as Class;
style.setStyle("upSkin",cls);
}
}
StyleManager.setStyleDeclaration(".buttonme",style,true);
}
When I apply this new style 'buttonme' to a button i am getting below error:
ArgumentError: Error #1063: Argument count mismatch on TickMark(). Expected 2, got 0.
Not sure why is this happening, and strange thing is, when I embed the same swf file it works, like below:
[Embed(source="styles.swf", symbol="Tick")]
private var GraphicClass:Class;
If I use the class GraphicClass in setStyleDeclaration, it works... but basically I want it dynamically.
Or there are other easy methods to skin (image) a flex button dynamically?
You should be able to set your skin like that dynamically. It probably has to do with your TickMark class. I'm assuming when you do style.setStyle("upSkin", cls);, that cls is TickMark and it has two required constructor args: TickMark(arg1:Object, arg2:Object). Is that true? Somewhere in the setStyle method its doing new cls().
If so, just make sure there's no constructor arguments and it should work.
If not, try following the stack trace and using breakpoints in Flex Builder if you don't already, that should help pinpoint the problem.
Best,
Lance
I believe, when you embed the export-symbol in your flex-app, it would be taking care of size and perhaps just embedding the png directly.
As your symbol-class extends BitmapData, it has to be instantiated by passing required arguments in constructor. So whatever error you get, is by design and work as expected.
You can wrap png in some other type of symbols (sprite, movieclip, etc) and export. That should work fine when used in setStyle (..,..)

clone flex component

I am trying to duplicate a flex component at run time.
For example if i have this
mx:Button label="btn" id="btn" click="handleClick(event)"/>
i should be able to call a function called DuplicateComponent() and it should return me a UI component thts exactly same as above button including the event listeners with it.
Can some one help me please??
Thanks in advance
Do a Byte Array Copy. This code segment should do it for you:
// ActionScript file
import flash.utils.ByteArray;
private function clone(source:Object):*
{
var myBA:ByteArray = new ByteArray();
myBA.writeObject(source);
myBA.position = 0;
return(myBA.readObject());
}
One note, I did not write this code myself, I'm pretty sure I got it from a post on the Flex Coder's list.
To solve that problem you should use actionscript and create the buttons dynamically.
Lets say you want the button(s) to go in a VBox called 'someVbox'
for (var i:uint = 0; i< 10; i++){
var but:Button = new Button();
but.label = 'some_id_'+i;
but.id = 'some_id_'+i;
but.addEventListener(MouseEvent.CLICK, 'handleClick');
someVbox.addChild(but);
}
I haven't tested it, but that should add 10 buttons to a vbox with a bit of luck.
You can't take a deep copy of UIComponents natively. You're best bet would be to create a new one and analyse the one you have to add a duplicate setup. To be honest this does sound like a bit of a code smell. I wonder if there may be a better solution to the problem with a bit of a rethink..
Same question as: http://www.flexforum.org/viewtopic.php?f=4&t=1421
Showing up in a google search for the same thing. So you've cut&pasted the same question a month later. No luck eh?
There is no easy way to do this that I know of. Many of a component's settings are dependent on the container/context/etc... and get instantiated during the creation process, so there's no reason to clone from that perspective.
You can clone key settings in actionscript and use those when creating new elements.
For instance, assuming you only care about properties, you might have an array ["styleName","width","height",...], and you can maybe use the array like this:
var newUI:UIComponent = new UIComponent();
for each(var s:String in propArray) {
newUI[s] = clonedUI[s];
}
If you want more bites on your question (rather than waiting a month), tell us what you are trying to achieve.
mx.utils.ObjectUtil often comes in handy, however for complex object types, it's typically good practice to implement an interface that requires a .clone() method, similar to how Events are cloned.
For example:
class MyClass implements ICanvasObject
{
...
public function clone():ICanvasObject
{
var obj:MyClass = new MyClass(parameters...);
return obj;
}
}
This gives your code more clarity and properly encapsulates concerns in the context of how the object is being used / cloned.
You are right but as per my understanding UI Components are not cloned by mx.utils.ObjectUtil.
from : http://livedocs.adobe.com/flex/201/langref/mx/utils/ObjectUtil.html#copy()
copy () method
public static function copy(value:Object):Object
Copies the specified Object and returns a reference to the copy. The copy is made using a native serialization technique. This means that custom serialization will be respected during the copy.
This method is designed for copying data objects, such as elements of a collection. It is not intended for copying a UIComponent object, such as a TextInput control. If you want to create copies of specific UIComponent objects, you can create a subclass of the component and implement a clone() method, or other method to perform the copy.
Parameters value:Object — Object that should be copied.
Returns Object — Copy of the specified Object

AS3 Memory Conservation (Loaders/BitmapDatas/Bitmaps/Sprites)

I'm working on reducing the memory requirements of my AS3 app. I understand that once there are no remaining references to an object, it is flagged as being a candidate for garbage collection.
Is it even worth it to try to remove references to Loaders that are no longer actively in use? My first thought is that it is not worth it.
Here's why:
My Sprites need perpetual references to the Bitmaps they display (since the Sprites are always visible in my app). So, the Bitmaps cannot be garbage collected. The Bitmaps rely upon BitmapData objects for their data, so we can't get rid of them. (Up until this point it's all pretty straightforward).
Here's where I'm unsure of what's going on:
Does a BitmapData have a reference to the data loaded by the Loader? In other words, is BitmapData essentially just a wrapper that has a reference to loader.content, or is the data copied from loader.content to BitmapData?
If a reference is maintained, then I don't get anything by garbage collecting my loaders...
Thoughts?
Using AMF a bit with third party products has lead me to believe the Loader class attempts to instantiate a new class of the given content type (in this case it would be a Bitmap class instance). You are probably constructing a new BitmapData object from your Bitmap instance. From that I would assume that the Loader instance references the Bitmap instance, and in your case your code also references the Bitmap instance. Unless at some point you are calling BitmapData.clone().
There are also a couple of ways to force GC. Force Garbage Collection in AS3?
You may find it useful to attach some arbitrarily large object to something, then force the GC to see if that thing is getting cleaned up or floating around. If you are using Windows something like procmon (http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx) is more helpful than task manager for doing this kind of external inspection.
This of course is a bit trial and error but for lack of something like Visual VM (https://visualvm.dev.java.net/) we are kind of screwed in the Flash world.
It's a good question, but to the best of my knowledge, the answer is no -- neither Bitmap nor BitmapData objects possess references to the loaders that load them, so you can safely use them without concern for their preventing your Loaders from being collected.
If you want to make absolutely sure, though, use the clone() method of the BitmapData class:
clone()
Returns a new BitmapData object that
is a clone of the original instance
with an exact copy of the contained
bitmap.
For example:
private function onCreationComplete():void
{
var urlRequest:URLRequest = new URLRequest("MyPhoto.jpg");
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loader_complete, false, 0, true);
loader.load(urlRequest);
}
private function loader_complete(event:Event):void
{
var img1:Image = new Image();
img1.source = Bitmap(event.target.content);
addChild(img1);
var img2:Image = new Image();
img2.source = new Bitmap(event.target.content.bitmapData.clone());
addChild(img2);
}
Here, img1's source is a Bitmap cast explicitly from the BitmapData object returned by the loader. (If you examine the references in FlexBuilder, you'll see they are identical.) But img2's source is a clone -- new bunch of bytes, new object, new reference.
Hope that helps explain things. The more likely culprits responsible for keeping objects from being garbage collected, though, are usually event handlers. That's why I set the useWeakReference flag (see above) when setting up my listeners, pretty much exclusively, unless I have good reason not to:
useWeakReference:Boolean (default =
false) — Determines whether the
reference to the listener is strong or
weak. A strong reference (the default)
prevents your listener from being
garbage-collected. A weak reference
does not.
you may set a variable in the complete listener that stores the bitmap and then destroy the object later
public function COMPLETEListener(e:Event){
myBitmap = e.target.loader.content;
}
public function destroy(){
if(myBitmap is Bitmap){
myBitmap.bitmapData.dispose();
}
}
works fine for me load some big image and see the difference in the taskmanager

How can you get NVelocity to initialize correctly?

I can't get NVelocity to initialize. I'm not trying to do anything complicated, so it's just fine if it initializes at the defaults, but it won't even do that.
This:
VelocityEngine velocity = new VelocityEngine();
ExtendedProperties props = new ExtendedProperties();
velocity.Init(props);
Results in: "It appears that no class was specified as the ResourceManager..."
So does this:
VelocityEngine velocity = new VelocityEngine();
velocity.Init();
I can find precious little documentation on what the properties should be, nor how to get it to initialize with the simple defaults. Can anyone point to a resource?
A lot of pages point back to this page:
http://www.castleproject.org/others/nvelocity/usingit.html
But this page skips over the (seemingly) most important point -- how to set the properties and what to set them to.
I just want to load a simple template from a file.
Here's what I found out --
I was using the original NVelocity library, which hasn't had an update since 2003. I think it's a dead project.
I switched to the Castle Project version, and it's much easier -- in fact, it runs much like the examples on the page I linked to. It seems to set intelligent defaults for properties. I can initialize it without any properties set, but the template directory defaults to ".", so I generally set that one (do it before running "init").
To get the correct DLL, you need to download the latest NVelocity release (as of this writing it's 1.1).
Castle Project Download Page
You need to include the following files in your assembly, and make sure that their type is set to "Resource"
src\Runtime\Defaults\directive.properties
src\Runtime\Defaults\nvelocity.properties
These will then be found by ResourceLocator
src\Runtime\Resource\Loader\ResourceLocator.cs
If you get an exception on GetManifestResourceNames() as I did when trying to run Dvsl, then try modifying the ResourceLocator constructor to catch and ignore the error since the required files are in your local assembly (if you included them above) and the exception is only thrown by external assemblies (no idea why).
foreach(Assembly a in assemblies) {
String prefix = a.FullName.Substring(0,a.FullName.IndexOf(",")).ToLower();
try
{
String[] names = a.GetManifestResourceNames();
foreach (String s in names)
{
if (s.ToLower().Equals(fn) || s.ToLower().Equals(prefix + "." + fn))
{
this.filename = s;
assembly = a;
isResource = true;
}
}
} catch {
}
}

Resources