Implementieren der IFilePromise-SchnittstelleAdobe AIR 2 und höher Zum Bereitstellen von Dateizusagen für Ressourcen, die sich nicht über ein URLFilePromise-Objekt aufrufen lassen, können Sie die IFilePromise-Schnittstelle in einer benutzerdefinierten Klasse implementieren. Die IFilePromise-Schnittstelle definiert die Methoden und Eigenschaften, die die AIR-Laufzeit für den Zugriff auf die Daten verwendet, die in eine Datei geschrieben werden sollen, wenn die Dateizusage abgelegt wird. Eine IFilePromise-Implementierung übergibt ein anderes Objekt an die AIR-Laufzeit, das die Daten für die Dateizusage bereitstellt. Dieses Objekt muss die IDataInput-Schnittstelle implementieren, die von der AIR-Laufzeit zum Lesen der Daten verwendet wird. Beispielsweise verwendet die URLFilePromise-Klasse, die IFilePromise implementiert, ein URLStream-Objekt als Datenprovider. AIR kann die Daten synchron oder asynchron lesen. Die IFilePromise-Implementierung meldet den unterstützten Zugriffsmodus durch Rückgabe des entsprechenden Wertes in der isAsync-Eigenschaft. Für den asynchronen Datenzugriff muss das Datenprovider-Objekt die IEventDispatcher-Schnittstelle implementieren und die erforderlichen Ereignisse auslösen, wie open, progress und complete. Als Datenprovider für eine Dateizusage können Sie eine benutzerdefinierte Klasse oder eine der folgenden integrierten Klassen verwenden:
Zum Implementieren der IFilePromise-Schnittstelle müssen Sie Code für die folgenden Funktionen und Eigenschaften angeben:
Alle IFilePromise-Methoden werden während einer Drag & Drop-Operation, die die Dateizusage umfasst, von der Laufzeit aufgerufen. Normalerweise sollte die Anwendungslogik keine dieser Methoden direkt aufrufen. Verwenden eines synchronen Datenprovider in einer DateizusageDie einfachste Methode zur Implementierung der IFilePromise-Schnittstelle ist die Verwendung eines synchronen Datenprovider-Objekts, wie ein ByteArray-Objekt oder ein synchrones FileStream-Objekt. Im folgenden Beispiel wird ein ByteArray-Objekt erstellt, mit Daten gefüllt und dann beim Aufruf der open()-Methode zurückgegeben. 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 der Praxis sind synchrone Dateizusagen nur von eingeschränktem Nutzen. Bei einer kleinen Datenmenge könnten Sie einfach eine Datei in einem temporären Verzeichnis erstellen und der Drag & Drop-Zwischenablage ein reguläres Dateilisten-Array hinzufügen. Wenn die Datenmenge jedoch groß ist oder wenn die Computerressourcen durch das Generieren der Daten stark beansprucht werden, ist ein langer synchroner Prozess erforderlich. Lange synchrone Prozesse können die Aktualisierung der Benutzeroberfläche deutlich verzögern, sodass der Eindruck entsteht, dass die Anwendung nicht reagiert. Um dieses Problem zu vermeiden, können Sie einen asynchronen Datenprovider erstellen, der von einem Timer gesteuert wird. Verwenden eines asynchronen Datenprovider in einer DateizusageBei Verwendung eines asynchronen Datenprovider-Objekts muss die isAsync-Eigenschaft von IFilePromise auf true eingestellt sein und das Objekt, das von der open()-Methode zurückgegeben wird, muss die IEventDispatcher-Schnittstelle implementieren. Die Laufzeit wartet auf mehrere alternative Ereignisse, sodass verschiedene integrierte Objekte als Datenprovider verwendet werden können. Beispielsweise werden progress-Ereignisse von FileStream- und URLStream-Objekten ausgelöst, während socketData-Ereignisse von Socket-Objekten ausgelöst werden. Die Laufzeit wartet auf die entsprechenden Ereignisse von allen diesen Objekten. Die folgenden Ereignisse steuern den Prozess zum Lesen der Daten aus dem Datenprovider-Objekt:
Der Datenprovider sollte diese Ereignisse in der folgenden Reihenfolge ausgeben:
Hinweis: Die integrierten Objekte, FileStream, Socket und URLStream, setzen die entsprechenden Ereignisse automatisch ab.
Im folgenden Beispiel wird eine Dateizusage mit einem benutzerdefinierten asynchronen Datenprovider erstellt. Die Datenprovider-Klasse erweitert ByteArray (für die IDataInput-Unterstützung) und implementiert die IEventDispatcher-Schnittstelle. Bei jedem Timer-Ereignis generiert das Objekt einen Datenblock und setzt ein progress-Ereignis ab, um die Laufzeit über die Verfügbarkeit der Daten zu informieren. Wenn ausreichend Daten generiert wurden, setzt das Objekt ein complete-Ereignis ab. 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 );
}
}
}
Hinweis: Da die AsyncDataProvider-Klasse im Beispiel ByteArray erweitert, kann sie nicht außerdem EventDispatcher erweitern. Zum Implementieren der IEventDispatcher-Schnittstelle verwendet die Klasse ein internes EventDispatcher-Objekt und leitet die IEventDispatcher-Methodenaufrufe an dieses interne Objekt weiter. Sie könnten auch EventDispatcher erweitern und IDataInput implementieren (oder Sie können beide Schnittstellen implementieren).
Die asynchrone IFilePromise-Implementierung ist mit der synchronen Implementierung fast identisch. Es bestehen die folgenden Hauptunterschiede: isAsync gibt true zurück und die open()-Methode gibt ein asynchrones Datenobjekt zurück: 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 );
}
}
}
|
|