Okay, here is one weird bug...
In my app, I load multiple xml files. And to load those, I always create a new URLLoader. Nothing special.
The first file works fine, the second one does, too. The third one, however, reports to have loaded fine, but the data it holds is actually the data of the second file. The current workaround is to load the third file twice, which somehow works... weird.
I have absolutely no clue how such a thing can happen. All three files are of course different files with different paths.
Here is the relevant class, hope it is of any use, if something is unclear, please ask. The DownloadJob class is merely a helper class that holds a String and a Function object. The latter one is called when the download is finished.
// Actual class stuff
private var _downloadQueue :Array = new Array();
/**
* Adds a download to the queue. Will be started immediatly.
* @param p_url The URL of the download.
* @param p_callback The function to call when the download is finished. Has to take a DisplayObject/Sound/String as first parameter.
*/
public function addDownload(p_url:String, p_callback:Function) :void
{
var job :DownloadJob = new DownloadJob(p_url, p_callback);
_downloadQueue.push(job);
debug.ttrace("added: " + job.url);
// If it is the only item, start downloading
if (_downloadQueue.length == 1)
{
var job :DownloadJob = DownloadJob(_downloadQueue[0]);
load(job);
}
}
/**
* Will call the callback and dispatch an event if all loading is done.
* @param p_event The event that is passed when a download was completed.
*/
private function downloadComplete(p_event:Event) :void
{
var job :DownloadJob = DownloadJob(_downloadQueue[0]);
var downloaded :Object = p_event.target;
_downloadQueue.splice(0, 1);
debug.ttrace("completed: " + job.url);
// Notify via callback
if (downloaded is LoaderInfo)
{
job.callback(downloaded.content);
}
else if (downloaded is Sound)
{
job.callback(downloaded);
}
else if (downloaded is URLLoader)
{
// This one holds the data of the previously loaded xml, somehow
job.callback(URLLoader(downloaded).data);
}
// Continue downloading if anything is left in the queue
if (_downloadQueue.length > 0)
{
var job :DownloadJob = DownloadJob(_downloadQueue[0]);
load(job);
}
else
{
dispatchEvent(new Event(EVENT_DOWNLOADS_FINISHED));
}
}
/**
* Will load the passed job immediatly.
* @param p_job The job to load.
*/
private function load(p_job:DownloadJob) :void
{
// Different loaders needed for data, sound and non-sound
if (p_job.url.indexOf(".xml") != -1 ||
p_job.url.indexOf(".txt") != -1)
{
var urlloader :URLLoader = new URLLoader();
urlloader.addEventListener(Event.COMPLETE, downloadComplete);
urlloader.addEventListener(IOErrorEvent.IO_ERROR, handleError);
urlloader.load(new URLRequest(p_job.url));
}
else if ( p_job.url.indexOf(".mp3") != -1 &&
p_job.url.indexOf(".flv") != -1)
{
var sound :Sound = new Sound();
sound.addEventListener(Event.COMPLETE, downloadComplete);
sound.addEventListener(IOErrorEvent.IO_ERROR, handleError);
sound.load(new URLRequest(p_job.url));
}
else
{
var loader :Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, downloadComplete);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, handleError);
loader.load(new URLRequest(p_job.url));
}
}
}
I spent some time on your class and could not find any errors, even when dispatching random addDownload
commands from a timer - everything went as expected, no mix-ups, no weird data residue. I can only guess that perhaps the issue has something to do with weird variable handling in ActionScript, if it really is within the code you posted at all.
So then I took the liberty of rearranging your Class a bit:
Vector.<DownloadJob>
. This lets us get rid of all the type casting.currentJob
. There will only be one job to work on at a time, anyway. This eliminates all the function arguments.currentJob
isn't null
, i.e. a download is actually in progress. We don't have to queue things, if there's no need to wait. This leaves only a single call to each push()
and splice()
. No more uncertainties in respect to when things get added and removed.Try to exchange the code below with your previous class and see if the problem still exists. If it does, I am pretty sure the problem exists outside of your loader, possibly in the callback functions that process the payload.
private static const EVENT_DOWNLOADS_FINISHED : String = "EVENT_DOWNLOADS_FINISHED";
private var currentJob : DownloadJob;
private var downloadQueue : Vector.<DownloadJob> = new Vector.<DownloadJob> ();
/**
* Adds a download to the queue. Will be started immediatly.
* @param url The URL of the download.
* @param callback The function to call when the download is finished. Has to take a DisplayObject/Sound/String as first parameter.
*/
public function addDownload ( url : String, callback : Function ) : void {
var job : DownloadJob = new DownloadJob ( url, callback );
if (currentJob) downloadQueue.push ( job );
else {
currentJob = job;
load ();
}
}
private function load () : void {
if ( jobIsText () ) loadText ();
else if ( jobIsSound () ) loadSound ();
}
private function jobIsText () : Boolean {
var url : String = currentJob.url;
return url.indexOf ( ".xml" ) != -1 || url.indexOf ( ".txt" ) != -1;
}
private function jobIsSound () : Boolean {
var url : String = currentJob.url;
return url.indexOf ( ".mp3" ) != -1;
}
private function loadText () : void {
var urlloader : URLLoader = new URLLoader ();
urlloader.addEventListener ( Event.COMPLETE, handleComplete );
urlloader.addEventListener ( IOErrorEvent.IO_ERROR, handleError );
urlloader.load ( new URLRequest ( currentJob.url ) );
}
private function loadSound () : void {
var sound : Sound = new Sound ();
sound.addEventListener ( Event.COMPLETE, handleComplete );
sound.addEventListener ( IOErrorEvent.IO_ERROR, handleError );
sound.load ( new URLRequest ( currentJob.url ) );
}
private function handleComplete ( ev : Event ) : void {
processPayload ( ev.target );
if (downloadQueue.length > 0) loadNext ();
else dispatchEvent ( new Event ( EVENT_DOWNLOADS_FINISHED ) );
}
private function handleError ( ev : Event ) : void {
trace ( "Error while downloading:" + currentJob.url );
}
private function processPayload ( loader : Object ) : void {
currentJob.callback ( getPayload ( loader ) );
currentJob = null;
}
private function loadNext () : void {
currentJob = downloadQueue.splice ( 0, 1 )[0];
load ();
}
private function getPayload ( loader : Object ) : Object {
return (loader is LoaderInfo) ? loader.content :
(loader is URLLoader) ? URLLoader ( loader ).data :
loader;
}