W przypadku użycia obiektu asynchronicznego dostawcy danych właściwość
isAsync
obiektu IFilePromise musi być równa
true
, a obiekt zwrócony przez metodę
open()
musi implementować interfejs IEventDispatcher. Środowisko wykonawcze wykrywa kilka alternatywnych zdarzeń, tak że w charakterze dostawców danych można użyć różnych obiektów wbudowanych. Na przykład zdarzenia
progress
są wywoływane przez obiekty FileStream i URLStream, natomiast zdarzenia
socketData
są wywoływane przez obiekty Socket. Środowisko wykonawcze wykrywa odpowiednie zdarzenia ze wszystkich tych obiektów.
Następujące zdarzenia sterują procesem odczytywania danych z obiektu dostawcy danych:
-
Event.OPEN — informuje środowisko wykonawcze, że źródło danych jest gotowe.
-
ProgressEvent.PROGRESS — informuje środowisko wykonawcze o dostępności danych. Środowisko wykonawcze odczyta dostępną ilość danych z obiektu dostawcy danych.
-
ProgressEvent.SOCKET_DATA — informuje środowisko wykonawcze o dostępności danych. Zdarzenie
socketData
jest wywoływane przez obiekty działające w oparciu o gniazda. Obiekty innego typu powinny wywoływać zdarzenia
progress
. (Środowisko wykonawcze wykrywa oba typy zdarzeń informujących o możliwości odczytu danych).
-
Event.COMPLETE — informuje środowisko wykonawcze, że wszystkie dane zostały odczytane.
-
Event.CLOSE — informuje środowisko wykonawcze, że wszystkie dane zostały odczytane. (Środowisko wykonawcze wykrywa zarówno zdarzenia
close
, jak i
complete
).
-
IOErrorEvent.IOERROR — informuje środowisko wykonawcze, że wystąpił błąd podczas odczytu danych. Środowisko wykonawcze przerywa tworzenie pliku i wywołuje metodę IFilePromise
close()
.
-
SecurityErrorEvent.SECURITY_ERROR — informuje środowisko wykonawcze, że wystąpił błąd zabezpieczeń. Środowisko wykonawcze przerywa tworzenie pliku i wywołuje metodę IFilePromise
close()
.
-
HTTPStatusEvent.HTTP_STATUS — używane przez środowisko wykonawcze razem z wartością
httpResponseStatus
w celu potwierdzenia, że dostępne dane są pożądaną treścią, a nie komunikatem o błędzie (takim jak strona błędu nr 404). To zdarzenie powinny wywoływać obiekty oparte na protokole HTTP.
-
HTTPStatusEvent.HTTP_RESPONSE_STATUS — używane przez środowisko wykonawcze razem z wartością
httpStatus
w celu potwierdzenia, że dostępne dane reprezentują pożądaną treść. To zdarzenie powinny wywoływać obiekty oparte na protokole HTTP.
Dostawca danych powinien wywoływać te zdarzenia w następującej kolejności:
-
zdarzenie
open
-
zdarzenia
progress
lub
socketData
;
-
zdarzenie
complete
lub
close
.
Uwaga:
Wbudowane obiekty FileStream, Socket i URLStream automatycznie wywołują odpowiednie zdarzenia.
Poniższy przykład ilustruje tworzenie obietnicy pliku korzystającej z niestandardowego synchronicznego dostawcy danych. Klasa dostawcy danych rozszerza klasę ByteArray (w celu zaimplementowania interfejsu IDataInput) oraz implementuje interfejs IEventDispatcher. Przy każdym zdarzeniu licznika czasu obiekt generuje fragment danych i wywołuje zdarzenie progress, aby poinformować środowisko wykonawcze o dostępności danych. Po wygenerowaniu dostatecznej ilości danych obiekt wywołuje zdarzenie complete.
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 );
}
}
}
Uwaga:
Ponieważ klasa AsyncDataProvider w tym przykładzie rozszerza klasę ByteArray, nie może jednocześnie rozszerzać klasy EventDispatcher. Do zaimplementowania interfejsu IEventDispatcher wykorzystano wewnętrzny obiekt EventDispatcher, a wywołania interfejsu IEventDispatcher są przekazywane do tego wewnętrznego obiektu. Można również rozszerzyć klasę EventDispatcher i zaimplementować interfejs IDataInput (lub zaimplementować oba interfejsy).
Asynchroniczna implementacja interfejsu IFilePromise niemal nie różni się od implementacji synchronicznej. Główna różnica polega na tym, że właściwość
isAsync
zwraca wartość
true
, a metoda
open()
zwraca asynchroniczny obiekt danych:
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 );
}
}
}