I have written the following class to abstract multiple calls to my server for sending data to a database and getting that data back.
package {
import flash.net.URLRequest;
import flash.net.URLLoader;
import flash.events.*;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLVariables;
import flash.net.URLRequestMethod;
import flash.net.URLLoaderDataFormat;
public class sqlReq extends URLLoader {
private var phpVars: URLVariables;
private var phpFileRequest: URLRequest;
private var phpLoader: URLLoader;
private var tempPhpVars: String;
private var totalBytes: uint;
public function sqlReq(link: String, dataVars: String) {
// constructor code
phpVars = new URLVariables();
phpFileRequest = new URLRequest(link);
phpFileRequest.method = URLRequestMethod.POST;
phpLoader = new URLLoader();
phpLoader.dataFormat = URLLoaderDataFormat.TEXT;
phpLoader.addEventListener(Event.COMPLETE, phpReqCompleted);
phpLoader.addEventListener(IOErrorEvent.IO_ERROR, phpReqError);
phpLoader.addEventListener(IOErrorEvent.NETWORK_ERROR, phpReqNetworkError);
phpLoader.addEventListener(ProgressEvent.PROGRESS, phpReqprogress);
//phpLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, phpReqErrorhttpStatus);
phpFileRequest.data = dataVars;
phpLoader.load(phpFileRequest);
}
private function phpReqCompleted(event: Event): void {
//trace("returned vars",event.target.data);
tempPhpVars = event.target.data;
this.dispatchEvent(new Event(Event.COMPLETE));
clearEvents();
}
private function phpReqError(event: IOErrorEvent): void {
this.dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR));
tempPhpVars = "resultIs:" + event.target.data;
//trace("Code Confirmed: " + event);
}
public function phpReqResults(): String {
return tempPhpVars;
}
public function ByteAmount(): uint {
return totalBytes;
}
private function phpReqprogress(event: ProgressEvent): void {
//trace(event.bytesLoaded, "total ", event.bytesTotal);
totalBytes = event.bytesTotal;
this.dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS));
}
private function phpReqNetworkError(event: IOErrorEvent): void {
this.dispatchEvent(new IOErrorEvent(IOErrorEvent.NETWORK_ERROR));
//phpVars = event.target.data;
//trace("Code Confirmed: " + event);
}
private function clearEvents(): void {
phpLoader.removeEventListener(Event.COMPLETE, phpReqCompleted);
phpLoader.removeEventListener(IOErrorEvent.IO_ERROR, phpReqError);
phpLoader.removeEventListener(IOErrorEvent.NETWORK_ERROR, phpReqNetworkError);
phpLoader.removeEventListener(ProgressEvent.PROGRESS, phpReqprogress);
//phpLoader.removeEventListener(HTTPStatusEvent.HTTP_STATUS, phpReqErrorhttpStatus);
phpVars = null;
phpLoader = null;
phpFileRequest = null;
}
}
}
The code has been working flawlessly, until recently, I noticed something strange. For example, when I make multiple requests back to back, the second sql request gets the data of the previous sql request. If I create timer and wait, everything is fine, but I do need to be able to send multiple requests and I should expect different results for the different requests.
And these are the calls I make in the app (I do import all necessary classes so the code runs fine). The main issue: once in a while (more often than not), getName would return null and getAge would work, other times, getAge would return null and getName would work. If I call these functions separately, they ALWAYS work. Is there anything I am missing.
var sql:sqlReq;
var myTimer: Timer = new Timer(500, 20);
myTimer.addEventListener(TimerEvent.TIMER, onTick);
myTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onTimeUp);
function getName():void{
sql= new sqlReq("http://mysite.php","&user=Sarah");
sql.addEventListener(Event.COMPLETE,gotMyName);
sql.addEventListener(IOErrorEvent.IO_ERROR,ErrorGettingMyName);
}
function getAge():void{
sql= new sqlReq("http://mysite.php","&age=32");
sql.addEventListener(Event.COMPLETE,gotMyAge);
sql.addEventListener(IOErrorEvent.IO_ERROR,ErrorGettingMyAge);
}
function gotMyName(event:Event):void{
//All good
}
function gotMyAge(event:Event):void{
//All good
}
function ErrorGettingMyName(event:IOErrorEvent):void{
//All bad
}
function ErrorGettingMyAge(event:IOErrorEvent):void{
//All bad
}
function onTick(event:TimerEvent):void{
getName();
getAge();
}
function onTimeUp(event:TimerEvent):void{
//clear and remove timer events
}
If I were to devise such a system, I'd do the following (there might be some errors in the code since I stopped doing AS3 some 7 years ago, but the logic of how it supposed to be should be solid so I believe in you figuring it all out):
First, I wouldn't put the network request itself into the constructor, but rather into a separate method. Why? Flash is asynchronous, you never know WHEN the events fire, better safe than sorry:
phpLoader.addEventListener(ProgressEvent.PROGRESS, phpReqprogress);
//phpLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, phpReqErrorhttpStatus);
}
public function request(): void
{
phpFileRequest.data = dataVars;
phpLoader.load(phpFileRequest);
}
Then, the Array to keep the requests while they are running:
var SQLs: Array = new Array;
function isActive(sql: sqlReq): Boolean
{
var index: int = SQLs.indexOf(sql);
return index > -1;
}
// Single gate to delete the sqlReq instance.
function removeRequest(sql: sqlReq, completeHandler: Function, errorHandler: Function): void
{
var index: int = SQLs.indexOf(sql);
if (index < 0)
{
return;
}
SQLs.splice(index, 1);
// Unsubscribe from events.
sql.removeEventListener(Event.COMPLETE, completeHandler);
sql.removeEventListener(IOErrorEvent.IO_ERROR, errorHandler);
}
So, when you create new requests, you do as following:
function getName(): void
{
var sql: sqlReq = new sqlReq("http://mysite.php","&user=Sarah");
// Store the instance.
SQLs.push(sql);
// Subscribe for the events.
sql.addEventListener(Event.COMPLETE, gotMyName);
sql.addEventListener(IOErrorEvent.IO_ERROR, ErrorGettingMyName);
// Run the request.
sql.request();
}
Then, in (all) the handlers you need to do:
function gotMyName(event: Event): void
{
// Get reference to the author of the event.
var sql: sqlReq = event.target as sqlReq;
// Check if it is an active request and not some rogue.
if (!isActive(sql))
{
// Do not process the request if you cannot identify it.
return;
}
// All good.
// ...
// Your code here.
// Put the request to the rest.
removeRequest(sql, gotMyName, ErrorGettingMyName);
}