Implementazione dell'interfaccia IFilePromiseAdobe AIR 2 e versioni successive Per fornire promesse di file per risorse a cui non è possibile accedere utilizzando un oggetto URLFilePromise, potete implementare l'interfaccia IFilePromise in una classe personalizzata. L'interfaccia IFilePromise definisce i metodi e le proprietà utilizzati dal runtime AIR per accedere ai dati da scrivere in un file dopo che la promessa di file è stata rilasciata. Un'implementazione IFilePromise passa un altro oggetto al runtime AIR che fornisce i dati per la promessa di file. Questo oggetto implementa l'interfaccia IDataInput, utilizzata dal runtime AIR per leggere i dati. Ad esempio, la classe URLFilePromise, che implementa IFilePromise, utilizza un oggetto URLStream come fornitore dei dati. AIR può leggere i dati in maniera sincrona o asincrona. L'implementazione IFilePromise segnala quale modalità di accesso è supportata restituendo il valore appropriato nella proprietà isAsync. Se è disponibile l'accesso dati asincrono, l'oggetto fornitore di dati deve implementare l'interfaccia IEventDispatcher e inviare gli eventi necessari, ad esempio open, progress e complete. Potete utilizzare una classe personalizzata, o una delle classi incorporate seguenti, come fornitore di dati per una promessa di file:
Per implementare l'interfaccia IFilePromise, dovete fornire il codice per le funzioni e proprietà seguenti:
Tutti i metodi IFilePromise vengono chiamati dal runtime durante un'operazione di trascinamento che coinvolge la promessa di file. In genere, la logica dell'applicazione non deve essere chiamata direttamente da nessuno di questi metodi. Utilizzo di un fornitore di dati sincrono in una promessa di fileIl modo più semplice per implementare l'interfaccia IFilePromise è utilizzare un oggetto fornitore di dati sincrono, ad esempio un ByteArray o un FileStream sincrono. Nell'esempio seguente, un oggetto ByteArray viene creato, compilato con i dati e restituito quando viene chiamato il metodo open(). package
{
import flash.desktop.IFilePromise;
import flash.events.ErrorEvent;
import flash.utils.ByteArray;
import flash.utils.IDataInput;
public class SynchronousFilePromise implements IFilePromise
{
private const fileSize:int = 5000; //size of file data
private var filePath:String = "SynchronousFile.txt";
public function get relativePath():String
{
return filePath;
}
public function get isAsync():Boolean
{
return false;
}
public function open():IDataInput
{
var fileContents:ByteArray = new ByteArray();
//Create some arbitrary data for the file
for( var i:int = 0; i < fileSize; i++ )
{
fileContents.writeUTFBytes( 'S' );
}
//Important: the ByteArray is read from the current position
fileContents.position = 0;
return fileContents;
}
public function close():void
{
//Nothing needs to be closed in this case.
}
public function reportError(e:ErrorEvent):void
{
trace("Something went wrong: " + e.errorID + " - " + e.type + ", " + e.text );
}
}
}
In pratica, le promesse di file sincrone hanno un'utilità limitata. Se la quantità di dati è piccola, potete facilmente creare un file in una directory temporanea e aggiungere un normale array elenco file agli Appunti di trascinamento. Se, invece, la quantità di dati è grande o generare i dati richiede notevoli risorse di calcolo, è necessario un lungo processo sincrono. I processi sincroni lunghi possono bloccare gli aggiornamenti dell'interfaccia utente per un periodo di tempo ragguardevole durante il quale l'applicazione non è in grado di rispondere. Per evitare questo problema, potete creare un fornitore di dati asincrono basato su un timer. Utilizzo di un fornitore di dati asincrono in una promessa di fileQuando utilizzate un oggetto fornitore di dati asincrono, la proprietà isAsync di IFilePromise deve essere impostata su true e l'oggetto restituito dal metodo open() deve implementare l'interfaccia IEventDispatcher. Il runtime intercetta eventi alternativi in modo da poter utilizzare oggetti incorporati diversi come fornitore di dati. Ad esempio, gli eventi progress vengono inviati dagli oggetti FileStream e URLStream, mentre gli eventi socketData vengono inviati da oggetti Socket. Il runtime intercetta gli eventi appropriati da tutti questi oggetti. Gli eventi seguenti guidano il processo di lettura dei dati dall'oggetto fornitore di dati:
Il fornitore di dati deve inviare questi eventi nella sequenza seguente:
Nota: gli oggetti incorporati, FileStream, Socket e URLStream, inviano gli eventi appropriati automaticamente.
Nell'esempio seguente viene creata una promessa di file utilizzando un fornitore di dati asincrono personalizzato. La classe del fornitore di dati estende ByteArray (per il supporto IDataInput) e implementa l'interfaccia IEventDispatcher. A ogni evento del timer, l'oggetto genera una porzione di dati e invia un evento progress per informare il runtime che i dati sono disponibili. Quando è stato prodotto un numero di dati sufficiente, l'oggetto invia un evento 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 );
}
}
}
Nota: poiché la classe AsyncDataProvider nell'esempio estende ByteArray, non può estendere anche EventDispatcher. Per implementare l'interfaccia IEventDispatcher, la classe utilizza un oggetto EventDispatcher interno e inoltra le chiamate al metodo IEventDispatcher a tale oggetto. Potete anche estendere EventDispatcher e implementare IDataInput (o implementare entrambe le interfacce).
L'implementazione IFilePromise asincrona è quasi identica a quella sincrona. Le differenze principali sono che isAsync restituisce true e che il metodo open() restituisce un oggetto dati asincrono: 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 );
}
}
}
|
|