Implementación de la interfaz IFilePromiseAdobe AIR 2 y posterior Para proporcionar promesas de archivo a recursos a los que no se puede acceder utilizando un objeto URLFilePromise, es posible implementar la interfaz IFilePromise en una clase personalizada. La interfaz IFilePromise define los métodos y las propiedades utilizadas por el motor de ejecución de AIR para acceder a los datos que se escribirán en un archivo una vez colocada la promesa de archivo. Una implementación de IFilePromise transmite otro objeto al motor de ejecución de AIR que proporciona los datos para la promesa de archivo. Este objeto debe implementar la interfaz IDataInput, que el motor de ejecución de AIR utiliza para leer los datos. Por ejemplo, la clase URLFilePromise, que implementa IFilePromise, usa un objeto URLStream como proveedor de datos. AIR puede leer los datos de forma sincrónica o asíncrona. La implementación de IFilePromise indica qué modo de acceso se admite devolviendo el valor adecuado en la propiedad isAsync. Si se proporciona un acceso asíncrono a los datos, el objeto proveedor de datos debe implementar la interfaz IEventDispatcher y distribuir los eventos necesarios como, por ejemplo, open, progress y complete. Se puede utilizar una clase personalizada o una de las siguientes clases incorporadas, como proveedor de datos para una promesa de archivo:
Para implementar la interfaz IFilePromise, es necesario proporcionar código para las siguientes funciones y propiedades:
Todos los métodos IFilePromise se llaman mediante el motor de ejecución durante una operación de arrastrar y colocar que implica la promesa de archivo. Generalmente la lógica de la aplicación no debe llamar a ninguno de estos métodos directamente. Uso de un proveedor de datos sincrónico en una promesa de archivoLa forma más sencilla de implementar la interfaz IFilePromise consiste en utilizar un objeto proveedor de datos sincrónico como, por ejemplo, ByteArray o FileStream. En el siguiente ejemplo se crea un objeto ByteArray, relleno de datos, y se devuelve cuando se llama al método 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 );
}
}
}
En la práctica, las promesas de archivo sincrónicas presentan una utilidad limitada. Si la cantidad de datos es pequeña, se puede crear fácilmente un archivo en un directorio temporal y añadir un conjunto de lista de archivos normal al portapapeles de arrastrar y colocar. Por otra parte, si la cantidad de información es grande o la generación de datos requiere mucho procesamiento, es necesario contar un proceso sincrónico largo. Los procesos sincrónicos largos pueden bloquear las actualizaciones de la IU durante una cantidad considerable de tiempo y hacer que la aplicación no responda. Para evitar este problema, se puede crear un proveedor de datos asíncrono controlado por un temporizador. Uso de un proveedor de datos asíncrono en una promesa de archivoCuando se utiliza un objeto proveedor de datos asíncrono, la propiedad isAsync de IFilePromise se debe establecer en true y el objeto devuelto por el método open() debe implementar la interfaz IEventDispatcher. El motor de ejecución detecta varios eventos alternativos de modo que los distintos objetos incorporados se puedan utilizar como proveedores de datos. Por ejemplo, los eventos progress se distribuyen mediante los objetos FileStream y URLStream, mientras que los eventos socketData se distribuyen a través de los objetos Socket. El motor de ejecución detecta los eventos apropiados a partir de todos estos objetos. Los siguientes eventos controlan el proceso de lectura de datos desde el objeto proveedor:
El proveedor de datos debe distribuir estos eventos en la siguiente secuencia:
Nota: los objetos incorporados, FileStream, Socket y URLStream distribuyen los eventos adecuados de forma automática.
En el siguiente ejemplo se crea una promesa de archivo utilizando un proveedor de datos asíncrono y personalizado. La clase del proveedor de datos amplía ByteArray (para la compatibilidad con IDataInput) e implementa la interfaz IEventDispatcher. En cada evento del temporizador, el objeto genera un campo de datos y distribuye un evento de progreso para indicar al motor de ejecución que los datos están disponibles. Una vez generados datos suficientes, el objeto distribuye un evento completo. 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: debido a que la clase AsyncDataProvider del ejemplo amplía ByteArray, no puede ampliar también EventDispatcher. Para implementar la interfaz IEventDispatcher, la clase utiliza un objeto interno EventDispatcher y reenvía las llamadas del método IEventDispatcher a ese objeto interno. También se puede ampliar EventDispatcher e implementar IDataInput (o implementar ambas interfaces).
La implementación asíncrona de IFilePromise resulta casi idéntica a la implementación sincrónica. Las principales diferencias radican en que isAsync devuelve el valor true y que el método open() devuelve un objeto de datos asíncrono: 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 );
}
}
}
|
|