Implémentation de l’interface IFilePromiseAdobe AIR 2 et ultérieur Pour associer des fichiers promis aux ressources auxquelles il est impossible d’accéder par le biais d’un objet URLFilePromise, vous pouvez implémenter l’interface IFilePromise dans une classe personnalisée. L’interface IFilePromise définit les méthodes et propriétés utilisées par le moteur d’exécution AIR pour accéder aux données à écrire dans un fichier une fois le fichier promis déposé. Une implémentation d’IFilePromise transmet un autre objet au moteur d’exécution AIR qui fournit les données associées au fichier promis. Cet objet doit implémenter l’interface IDataInput, utilisée par le moteur d’exécution AIR pour lire les données. Par exemple, la classe URLFilePromise, qui implémente IFilePromise, fait appel à un objet URLStream en tant que fournisseur de données. AIR peut lire les données en mode synchrone et asynchrone. L’implémentation d’IFilePromise indique le mode d’accès pris en charge en renvoyant la valeur correspondante dans la propriété isAsync. Si un accès asynchrone aux données est proposé, l’objet fournisseur de données doit implémenter l’interface IEventDispatcher et distribuer les événements requis, tels que open, progress et complete. Vous pouvez utiliser une classe personnalisée ou l’une des classes intégrées suivantes en tant que fournisseur de données associé à un fichier promis :
Pour implémenter l’interface IFilePromise, vous devez fournir le code des fonctions et propriétés suivantes :
Toutes les méthodes IFilePromise sont appelées par le moteur d’exécution dans le cadre d’une opération glisser-déposer qui concerne le fichier promis. En règle générale, la logique de l’application ne devrait pas appeler directement ces méthodes. Utilisation d’un fournisseur de données synchrone dans un fichier promisLa technique d’implémentation de l’interface IFilePromise la plus simple consiste à utiliser un objet fournisseur de données synchrone tel que ByteArray ou un objet FileStream synchrone. Dans l’exemple suivant, un objet ByteArray est créé, rempli de données et renvoyé lorsque la méthode open() est appelée. 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 pratique, les fichiers promis synchrones sont d’une utilité limitée. Si le volume de données est réduit, il est tout aussi simple de créer un fichier dans un répertoire temporaire et d’ajouter un tableau contenant une liste de fichiers standard au Presse-papiers glisser-déposer. En revanche, si le volume de données est élevé ou que la génération de données sollicite d’importantes ressources informatiques, un long processus synchrone s’impose. Les longs processus synchrones risquent de bloquer les mises à jour de l’interface utilisateur pendant une durée prolongée. L’application semble alors non réactive. Pour parer à ce problème, vous pouvez créer un fournisseur de données asynchrone piloté par une horloge. Utilisation d’un fournisseur de données asynchrone dans un fichier promisLorsque vous utilisez un objet fournisseur de données asynchrone, la propriété isAsync d’IFilePromise doit être définie sur true et l’objet renvoyé par la méthode open() doit implémenter l’interface IEventDispatcher. Le moteur d’exécution écoute plusieurs événements, permettant ainsi d’utiliser divers objets intégrés en tant que fournisseurs de données. Les événements progress sont, par exemple, distribués par les objets FileStream et URLStream, alors que les événements socketData sont distribués par les objets Socket. Le moteur d’exécution écoute les événements appropriés qui émanent de tous ces objets. Les événements suivants étayent le processus de lecture des données à partir de l’objet fournisseur de données :
Le fournisseur de données doit distribuer ces événements dans l’ordre suivant :
Remarque : les objets intégrés, FileStream, Socket et URLStream, distribuent automatiquement les événements appropriés.
L’exemple suivant crée un fichier promis en faisant appel à un fournisseur de données asynchrone personnalisé. La classe du fournisseur de données constitue une extension de ByteArray (pour la prise en charge d’IDataInput) et implémente l’interface IEventDispatcher. A chaque événement associé à l’horloge, l’objet génère un bloc de données et distribue un événement « progress » pour avertir le moteur d’exécution que les données sont disponibles. Lorsque le volume de données produit est suffisant, l’objet distribue un événement « 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 ); } } } Remarque : puisque la classe AsyncDataProvider utilisée dans l’exemple constitue une extension de ByteArray, elle ne peut pas étendre également EventDispatcher. Pour implémenter l’interface IEventDispatcher, la classe fait appel à un objet EventDispatcher interne et transmet à ce dernier les appels de la méthode IEventDispatcher. Vous pouvez également étendre EventDispatcher et implémenter IDataInput (voire implémenter les deux interfaces).
L’implémentation asynchrone d’IFilePromise est quasiment identique à l’implémentation synchrone, à quelques différences près : isAsync renvoie true et la méthode open() renvoie un objet de données asynchrone : 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 ); } } } |
|