AS3: memory leak with two loaders - actionscript-3

I have a AS3 file with only one frame. Here is the code :
stop();
trace("Debut du code.");
var chargeur:Loader = new Loader();
var chargeur2:Loader = new Loader();
var adress:URLRequest = new URLRequest("img/idle.swf");
chargeur.load(adress);
addChild(chargeur);
chargeur.contentLoaderInfo.addEventListener(Event.COMPLETE,isLoaded)
function isLoaded (evt:Event) {
trace("Loading complete");
var adress2:URLRequest = new URLRequest("img/oldcoucou.swf");
chargeur2.load(adress2);
addChild(chargeur2);
}
Problem is : there is a memory leak , something like 3mo/s... and I can't figure why and what I'm doing wrong. Any clues ?
Thanks.
Edit:
With only one loader, I don't have the memory leak. If I load two, then hide one (chargeur.visible=false or chargeur.y=1200), no memory leak either. The problem occurs only when there is 2 visible at the same time. That sounds crazy, I know... I was hoping it was a know bug or a mistake in the code...

Assuming the loaded .swf's don't include any memory leaks the following code should be leak free.
stop();
trace("Debut du code.");
var chargeur:Loader = new Loader();
var chargeur2:Loader = new Loader();
var adress:URLRequest = new URLRequest("img/idle.swf");
var adress2:URLRequest = new URLRequest("img/oldcoucou.swf");
chargeur.contentLoaderInfo.addEventListener(Event.COMPLETE,isLoaded, false, 0, true);
chargeur.load(adress);
function isLoaded (evt:Event):void {
chargeur.contentLoaderInfo.removeEventListener(Event.COMPLETE,isLoaded);
adress = null;
trace("Loading1 complete");
addChild(chargeur);
chargeur2.contentLoaderInfo.addEventListener(Event.COMPLETE,isLoaded2, false, 0, true);
chargeur2.load(adress2);
}
function isLoaded2 (evt:Event):void {
chargeur2.contentLoaderInfo.removeEventListener(Event.COMPLETE,isLoaded2);
adress2 = null;
trace("Loading2 complete");
addChild(chargeur2);
}

I think it is impossible.
I guess the swf one be loaded into your program, it immediately run itself's program, it were that
it load other swf , swf A load swf B, swf B load swf A ....... \n. it's like a endless recusion function causing the stack overflow.

Related

Go to specific frame after external swf has been loaded AS3

I have been looking for solutions around here but I can't seem to get it right.
Basically I am trying to load an external swf after clicking on a 'Next' button and it will automatically go to a specific frame eg. frame 8 instead of frame 1.
At first I've got an error of using of using MovieClip function in a Loader and such.
Here's my code
nextBtn.addEventListener(MouseEvent.CLICK, fl_ClickToLoadUnloadSWF_1);
var fl_Loader1:Loader;
var fl_ToLoad1:Boolean = true;
function fl_ClickToLoadUnloadSWF_1(event:MouseEvent):void
{
if(fl_ToLoad1)
{
fl_Loader1 = new Loader();
fl_Loader1.load(new URLRequest("projectnowd.swf"));
addChild(fl_Loader1);
var fl_Loader1:MovieClip = event.target.content as MovieClip;
fl_Loader1.gotoAndStop(8);
}
else
{
fl_Loader1.unload();
removeChild(fl_Loader1);
fl_Loader1 = null;
}
fl_ToLoad1 = !fl_ToLoad1;
}
You can access content of loaded swf only after event. Complete was dispatched while loading swf file on to the stage.
Define event handler method to start from 8 th frame
function loaderCompleteHandler(evt:Event):void {
var loadedMovie:MovieClipp = evt.currentTarget.content as MovieClip;
loadedMovie.gotoAndStop(8);
}
Replace if block with below lines of code
if(fl_ToLoad1)
{
fl_Loader1 = new Loader();
fl_Loader1.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderCompleteHandler);
fl_Loader1.load(new URLRequest("projectnowd.swf"));
addChild(fl_Loader1);
}
Happy coding :)

How to save a cropped image on stage and load into another swf with air

i have a problem. The main problem is in my apk , there are 3 swf file.
first swf file decides who can be the second swf between swfA and swfB.
for example swfA is chosen. swfA takes a screenshot of an cropped area and load main swf again. i need to load this screenshot into main swf right now. but it is not visible on the screen. it doesnt load. where is the point that i miss ?
save an image code is : (class main for swf1)
public function takeScreenshot():void
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.utils.ByteArray;
import flash.net.FileReference;
import PNGEnc;
var myCroppedImage:Bitmap = crop(232, 121, 188, 570, this);
var d:BitmapData = new BitmapData(myCroppedImage.width, myCroppedImage.height);
d.draw(myCroppedImage);
var bild:ByteArray = PNGEnc.encode(d);
var newImage:File = File.applicationDirectory.resolvePath("app:/yeniResim.png");
var fileStream:FileStream = new FileStream();
fileStream.open(newImage , FileMode.UPDATE);
fileStream.writeBytes(bild);
fileStream.close();
//isimGoster.visible = false;
}
public function crop( _x:Number, _y:Number, _width:Number, _height:Number, displayObject:DisplayObject = null):Bitmap
{
var cropArea:Rectangle = new Rectangle( 0, 0, _width, _height );
var croppedBitmap:Bitmap = new Bitmap( new BitmapData( _width, _height ), PixelSnapping.ALWAYS, true );
croppedBitmap.bitmapData.draw( (displayObject!=null) ? displayObject : stage, new Matrix(1, 0, 0, 1, -_x, -_y) , null, null, cropArea, true );
return croppedBitmap;
}
load an image into another swf : (class main for swf 2)
public function frame4():void {
stop();
resim = new Loader();
var meRequest:URLRequest = new URLRequest('app:/yeniResim.png');
resim.load(meRequest);
var mce:MovieClip = resim.content as MovieClip;
mce.x = 480;
mce.y = 320;
}
It looks like you're not waiting for the Loader to finish loading the file before you access its content. For example, it is likely that "content" in this line below does not contain the loaded image at the time you try and use it:
var mce:MovieClip = resim.content as MovieClip;
It's been a long time since I did anything in Flash, so this code may not be quite right. But I'm very certain you need to do something like this:
var mce:MovieClip;
resim = new Loader();
resim.contentLoaderInfo.addEventListener(Event.COMPLETE, imgLoaded);
var meRequest:URLRequest = new URLRequest('app:/yeniResim.png');
resim.load(meRequest);
function imgLoaded(event:Event):void
{
mce = resim.content as MovieClip;
mce.x = 480;
mce.y = 320;
}
The other alternative is not waiting for the COMPLETE event and just adding the Loader to the stage. However, since you want to cast Loader.content into a MovieClip you need to wait for the content to be loaded. Check this example for more details.
It's also good to attach an event listener to handle any failures. Loader.contentLoaderInfo is a LoaderInfo object, you can see the other events that it dispatches in case you need to trouble shoot further.

as3 loaded swf accessing variables

I have some questions with sharing/using/accessing variables/functions between loaded swf files.
my prj consists of main.swf file and 2 swf's which I load on first init of the main.swf.
my questions are:
1.how can I use variables from 1.swf in 2.swf (function is running in 2.swf)
2.how can I call a function from 2.swf in 1.swf
here is the code I'm using to load the swf's:
var playerMc:MovieClip = new MovieClip();
var dbMc:MovieClip = new MovieClip();
var m2Loader:Loader = new Loader();
var mLoader:Loader = new Loader();
startLoad();
function startLoad()
{
//var mLoader:Loader = new Loader();
var mRequest:URLRequest = new URLRequest("./_player/player.swf");
mLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadMc);
mLoader.load(mRequest);
addChild(mLoader);
//var m2Loader:Loader = new Loader();
var m2Request = new URLRequest("./_db/db.swf");
m2Loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadMc2);
m2Loader.load(m2Request);
addChild(m2Loader);
}
function loadMc(event:Event):void
{
if (! event.target)
{
return;
}
playerMc = event.target.content as MovieClip;
mLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loadMc);
}
function loadMc2(event:Event):void
{
if (! event.target)
{
return;
}
dbMc = event.target.content as MovieClip;
dbMc.x = -400;
m2Loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loadMc2);
}
You have to stick with application domain.
In most cases you should load another swf in another application domain, but it's not really related to your question.
From loader, you must access to applicationDomain and then getDefinition. From there, you can get classes and use them in your main swf. Yes, you can read static properties.
If you need instances you should access loader#content. It is pointing to a root of loaded SWF. Root of loaded is SWF – is the instance of main class of the loaded swf.
Create a variable with no definition such as
public var MyClass;
as you can see i didnt add
public var MyClass:Class;
then in another function write
this.MyClass = this.mLoader.contentLoaderInfo.applicationDomain.getDefinition("NameOfClass") as Class;
i dont know much about this myself.. im having problems figuring out if you can only access Public static variables or if its possible to access normal public variables and possibly private variables because it is creating a new instance of the same class or however you want to word it..?
also after your write the above code .. when you want to change a varaibles this usually works for me
this.MyClass.RandomVariableName = this.MyClass.RandomVariableName + 1;
something like that..

AS3 maintime delay script while external swf loads and plays

I'm having an issue with playing an external SWFs inside the main SWF. Everything loads great, except not on cue. I'm using a simple delay actionscript to pause the main timeline until the external SWFs load, but it doesn't always sync up when testing in browsers.
Is there an AS3 code that I can use to pause the main timeline until the external SWF is finish loading and playing?
I need to do this multiple times through the movie, btw...
Below is the delay and the loadmovie array I'm using.
<--------------//Timer//--------------->
var timer4:Timer = new Timer(1500, 1);
timer4.addEventListener(
TimerEvent.TIMER,
function(evt:TimerEvent):void {
play();
}
);
timer4.start();
<--------------//loadMovie//--------------->
function startLoad()
{
var mLoader:Loader = new Loader();
var mRequest:URLRequest = new URLRequest('flip/note_flip.swf');
mLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteHandler);
mLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgressHandler);
mLoader.load(mRequest);
}
function onCompleteHandler(loadEvent:Event)
{
addChild(loadEvent.currentTarget.content);
}
function onProgressHandler(mProgress:ProgressEvent)
{
var percent:Number = mProgress.bytesLoaded/mProgress.bytesTotal;
trace(percent);
}
startLoad();
The load() method of the loader object is asynchronous. It means that the process will continue to execute next lines of code and loading is done independently. That's why you can see it's not on cue.
The simple way to fix your problem is to stop() all the loaded movies upon Event.COMPLETE and play() them once all the movies are loaded.
Use an array to store the loaded movies and address them once all movies are loaded.
And yeah, the timer hack is pointless, you won't know how long it will take the file to load, it can be different every time.
EDIT:
Let's assume that you've got N movie .swf files that makes a complete scene. You would like to load all of them, and once they're all loaded - play them.
Let's build a simple step-by-step logics:
1) First of all, we need a list of the URL pointing to where the external SWFs are.
2) Then we want to start loading the SWFs one by one (and not altogether) to prevent Flash Player bug of not loading some of the content AND keeping the order of movie clips aka z-index, depth, layer order etc.
3) On each loaded movie we count how many are still left to be loaded.
4) Once all movies are loaded, we play() all these movies.
Here's the code for you (written in a frame in case if you're not using classes and not familiar with OOP):
import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.display.MovieClip;
var linkArray:Array = ["1.swf", "2.swf", "3.swf"];
var loadedMovieArray:Array = [];
var totalMovies:int = linkArray.length;
var loadedMovies:int = 0;
var urlRequest:URLRequest = new URLRequest();
var l:Loader = new Loader();
l.contentLoaderInfo.addEventListener(Event.COMPLETE, onMovieLoaded);
loadMovies();
function loadMovies():void
{
var movieIndex:int = loadedMovies;
var movieURL:String = linkArray[movieIndex];
urlRequest.url = movieURL;
l.load(urlRequest);
}
function onMovieLoaded(e:Event):void
{
var loadedMC:MovieClip = l.content as MovieClip;
loadedMC.stop();
loadedMovieArray.push( loadedMC );
loadedMovies++;
if (loadedMovies == totalMovies)
onAllMoviesLoaded();
else
loadMovies();
}
function onAllMoviesLoaded():void
{
for (var i:int = 0; i < loadedMovieArray.length; i++) {
var mc:MovieClip = loadedMovieArray[i];
addChild(mc);
mc.play();
}
}

Refreshing every XX seconds

I am new to actionscript and flash, but i managed to make code that gets data from php file and refresh result every 30 seconds:
var timerRefreshRate:Number = 30000;
var fatherTime:Timer = new Timer(timerRefreshRate, 0);
fatherTime.addEventListener(TimerEvent.TIMER, testaa);
fatherTime.start();
function testaa(event:Event):void{
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.VARIABLES;
loader.addEventListener(Event.COMPLETE,varsLoaded);
loader.load(new URLRequest("data.php"));
function varsLoaded (event:Event):void {
this.opaqueBackground = loader.data.color;
title.text=loader.data.title;
banner_text.text=loader.data.text;
}
}
But now i am facing 2 problems:
1.) User must wait 30 seconds for movie to load first time
2.) Setting background color does not work any more.
What am i doing wrong?
You can call your function once to load immediately without waiting 30 seconds. Just change the parameters of the function to default to a null event:
function testaa(event:Event = null):void{
//...
}
Now you can call the function like so:
//...
fatherTime.start();
testaa();
So you start the timer but immediately run the function once.
For your second problem, the issue is most likely that you are using a nested function, so this does not refer to your class but rather the testaa function. Nested functions are bad practice in general and you should avoid them if possible. Move the function and loader reference outside and it should work. Final result should be something like this:
var loader:URLLoader;
var timerRefreshRate:Number = 30000;
var fatherTime:Timer = new Timer(timerRefreshRate, 0);
fatherTime.addEventListener(TimerEvent.TIMER, testaa);
fatherTime.start();
testaa();
function testaa(event:Event = null):void{
loader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.VARIABLES;
loader.addEventListener(Event.COMPLETE,varsLoaded);
loader.load(new URLRequest("data.php"));
}
function varsLoaded (event:Event):void {
this.opaqueBackground = loader.data.color;
title.text=loader.data.title;
banner_text.text=loader.data.text;
}