當您使用非同步資料提供者物件時,IFilePromise
isAsync
屬性必須是
true
而且
open()
方法傳回的物件必須實作 IEventDispatcher 介面。執行階段會偵聽多個替代事件,如此不同的內部物件就可以當做是資料提供者。例如,FileStream 和 URLStream 物件會傳送
progress
事件,而 Socket 物件會傳送
socketData
事件。執行階段會從這些所有的物件偵聽正確的事件。
以下事件會產生從資料提供者物件讀取資料的程序:
-
Event.OPEN — 通知執行階段資料來源已經就緒。
-
ProgressEvent.PROGRESS — 通知執行階段資料可以取得。 執行階段會從資料提供者物件讀取可用的資料量。
-
ProgressEvent.SOCKET_DATA — 通知執行階段資料可以取得。
socketData
事件是由通訊端式物件傳送的。至於其他物件類型,您應該傳送一個
progress
事件。(執行階段會偵聽這兩個事件,以便偵測何時可以讀取資料)。
-
Event.COMPLETE — 通知執行階段資料已經全部讀取了。
-
Event.CLOSE — 通知執行階段資料已經全部讀取了。(執行階段會為了這個目的來偵聽
close
和
complete
)。
-
IOErrorEvent.IOERROR — 通知執行階段讀取資料時發生錯誤。執行階段會中止建立檔案,然後呼叫 IFilePromise
close()
方法。
-
SecurityErrorEvent.SECURITY_ERROR — 通知執行階段發生安全性錯誤。 執行階段會終止建立檔案,然後呼叫 IFilePromise
close()
方法。
-
HTTPStatusEvent.HTTP_STATUS — 執行階段會將它與
httpResponseStatus
一起使用,以便確定可用的資料就是想要的內容,而不是錯誤訊息 (例如 404 網頁)。 以 HTTP 通訊協定為基礎的物件應傳送這個事件。
-
HTTPStatusEvent.HTTP_RESPONSE_STATUS — 執行階段會將它與
httpStatus
一起使用,以便確定可用的資料就是想要的內容。以 HTTP 通訊協定為基礎的物件應傳送這個事件。
資料提供者應該按照以下順序傳送這些事件:
-
open
事件
-
progress
或
socketData
事件
-
complete
或
close
事件
備註:
內建的物件、FileStream、Socket 以及 URLStream,會自動傳送正確的事件。
以下範例會使用自訂的非同步資料提供者來建立一個檔案承諾。 這種資料提供者類別會擴充 ByteArray (為了支援 IDataInput) 以及實作 IEventDispatcher 介面。在每一個計時器事件中,這個物件會產生一堆資料,然後傳送一個 progress 事件來通知執行階段資料可以取得。產生足夠的資料後,這個物件會傳送一個 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 );
}
}
}
備註:
因為本範例中的 AsyncDataProvider 類別擴充 ByteArray,所以它無法也擴充 EventDispatcher。 為了實作 IEventDispatcher 介面,這個類別會使用內部的 EventDispatcher 物件,然後將 IEventDispatcher 方法呼叫轉送至該內部物件。您也可以擴充 EventDispatcher 以及實作 IDataInput (或實作這兩個介面)。
非同步 IFilePromise 實作幾乎與同步實作完全相同。主要的差別在於
isAsync
會傳回
true
而
open()
方法會傳回非同步資料物件:
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 );
}
}
}