When you use an asynchronous data provider object, the IFilePromise
isAsync
property
must be
true
and the object returned by the
open()
method
must implement the IEventDispatcher interface. The runtime listens
for several alternative events so that different built-in objects
can be used as a data provider. For example,
progress
events
are dispatched by FileStream and URLStream objects, whereas
socketData
events
are dispatched by Socket objects. The runtime listens for the appropriate
events from all of these objects.
The following events drive the process of reading the data from
the data provider object:
-
Event.OPEN — Informs the runtime that the data source
is ready.
-
ProgressEvent.PROGRESS — Informs the runtime that data is
available. The runtime will read the amount of available data from
the data provider object.
-
ProgressEvent.SOCKET_DATA — Informs the runtime that data
is available. The
socketData
event is dispatched
by socket-based objects. For other object types, you should dispatch
a
progress
event. (The runtime listens for both
events to detect when data can be read.)
-
Event.COMPLETE — Informs the runtime that the data has all
been read.
-
Event.CLOSE — Informs the runtime that the data has all been
read. (The runtime listens for both
close
and
complete
for
this purpose.)
-
IOErrorEvent.IOERROR — Informs the runtime that an error
reading the data has occurred. The runtime aborts file creation
and calls the IFilePromise
close()
method.
-
SecurityErrorEvent.SECURITY_ERROR — Informs the runtime that
a security error has occurred. The runtime aborts file creation
and calls the IFilePromise
close()
method.
-
HTTPStatusEvent.HTTP_STATUS — Used, along with
httpResponseStatus
,
by the runtime to make sure that the data available represents the
desired content, rather than an error message (such as a 404 page).
Objects based on the HTTP protocol should dispatch this event.
-
HTTPStatusEvent.HTTP_RESPONSE_STATUS — Used, along with
httpStatus
,
by the runtime to make sure that the data available represents the
desired content. Objects based on the HTTP protocol should dispatch
this event.
The data provider should dispatch these events in the following
sequence:
-
open
event
-
progress
or
socketData
events
-
complete
or
close
event
Note:
The built-in objects, FileStream, Socket, and URLStream, dispatch
the appropriate events automatically.
The following example creates a file promise using a custom,
asynchronous data provider. The data provider class extends ByteArray
(for the IDataInput support) and implements the IEventDispatcher
interface. At each timer event, the object generates a chunk of
data and dispatches a progress event to inform the runtime that
the data is available. When enough data has been produced, the object dispatches
a complete event.
package
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.events.ProgressEvent;
import flash.events.TimerEvent;
import flash.utils.ByteArray;
import flash.utils.Timer;
[Event(name="open", type="flash.events.Event.OPEN")]
[Event(name="complete", type="flash.events.Event.COMPLETE")]
[Event(name="progress", type="flash.events.ProgressEvent")]
[Event(name="ioError", type="flash.events.IOErrorEvent")]
[Event(name="securityError", type="flash.events.SecurityErrorEvent")]
public class AsyncDataProvider extends ByteArray implements IEventDispatcher
{
private var dispatcher:EventDispatcher = new EventDispatcher();
public var fileSize:int = 0; //The number of characters in the file
private const chunkSize:int = 1000; //Amount of data written per event
private var dispatchDataTimer:Timer = new Timer( 100 );
private var opened:Boolean = false;
public function AsyncDataProvider()
{
super();
dispatchDataTimer.addEventListener( TimerEvent.TIMER, generateData );
}
public function begin():void{
dispatchDataTimer.start();
}
public function end():void
{
dispatchDataTimer.stop();
}
private function generateData( event:Event ):void
{
if( !opened )
{
var open:Event = new Event( Event.OPEN );
dispatchEvent( open );
opened = true;
}
else if( position + chunkSize < fileSize )
{
for( var i:int = 0; i <= chunkSize; i++ )
{
writeUTFBytes( 'A' );
}
//Set position back to the start of the new data
this.position -= chunkSize;
var progress:ProgressEvent =
new ProgressEvent( ProgressEvent.PROGRESS, false, false, bytesAvailable, bytesAvailable + chunkSize);
dispatchEvent( progress )
}
else
{
var complete:Event = new Event( Event.COMPLETE );
dispatchEvent( complete );
}
}
//IEventDispatcher implementation
public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
{
dispatcher.addEventListener( type, listener, useCapture, priority, useWeakReference );
}
public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
{
dispatcher.removeEventListener( type, listener, useCapture );
}
public function dispatchEvent(event:Event):Boolean
{
return dispatcher.dispatchEvent( event );
}
public function hasEventListener(type:String):Boolean
{
return dispatcher.hasEventListener( type );
}
public function willTrigger(type:String):Boolean
{
return dispatcher.willTrigger( type );
}
}
}
Note:
Because the AsyncDataProvider class in the example extends
ByteArray, it cannot also extend EventDispatcher. To implement the
IEventDispatcher interface, the class uses an internal EventDispatcher
object and forwards the IEventDispatcher method calls to that internal
object. You could also extend EventDispatcher and implement IDataInput
(or implement both interfaces).
The asynchronous IFilePromise implementation is almost identical
to the synchronous implementation. The main differences are that
isAsync
returns
true
and
that the
open()
method returns an asynchronous
data object:
package
{
import flash.desktop.IFilePromise;
import flash.events.ErrorEvent;
import flash.events.EventDispatcher;
import flash.utils.IDataInput;
public class AsynchronousFilePromise extends EventDispatcher implements IFilePromise
{
private var fileGenerator:AsyncDataProvider;
private const fileSize:int = 5000; //size of file data
private var filePath:String = "AsynchronousFile.txt";
public function get relativePath():String
{
return filePath;
}
public function get isAsync():Boolean
{
return true;
}
public function open():IDataInput
{
fileGenerator = new AsyncDataProvider();
fileGenerator.fileSize = fileSize;
fileGenerator.begin();
return fileGenerator;
}
public function close():void
{
fileGenerator.end();
}
public function reportError(e:ErrorEvent):void
{
trace("Something went wrong: " + e.errorID + " - " + e.type + ", " + e.text );
}
}
}