Implementatie van de IFilePromise-interface

Adobe AIR 2 of hoger

Als u bestandsbeloften beschikbaar wilt stellen voor resources die niet via een URLFilePromise-object toegankelijk zijn, kunt u de IFilePromise-interface in een aangepaste klasse implementeren. De IFilePromise-interface definieert de methoden en eigenschappen die in AIR worden gebruikt om toegang te krijgen tot de gegevens die naar een bestand moeten worden geschreven als de bestandsbelofte eenmaal is neergezet.

Een IFilePromise-implementatie geeft in AIR nog een object door dat de gegevens voor de bestandsbelofte levert. De IDataInput-interface moet door dit object worden geïmplementeerd. Deze interface wordt in AIR gebruikt om de gegevens te lezen. De URLFilePromise-klasse bijvoorbeeld, waardoor IFilePromise wordt geïmplementeerd, gebruikt een URLStream-object als de gegevensaanbieder.

AIR kan de gegevens synchroon of asynchroon lezen. De IFilePromise-implementatie rapporteert welke toegangsmodus wordt ondersteund door de juiste waarde in de eigenschap isAsync te retourneren. In geval van asynchrone gegevenstoegang moet het gegevensaanbiederobject de IEventDispatcher-interface implementeren en de benodigde gebeurtenissen verzenden, zoals open , progress en complete .

U kunt een aangepaste klasse of een van de volgende ingebouwde klassen gebruiken als gegevensaanbieder voor een bestandsbelofte:

  • ByteArray (synchroon)

  • FileStream (synchroon of asynchroon)

  • Socket (asynchroon)

  • URLStream (asynchroon)

Om de IFilePromise-interface te implementeren moet u code voor de volgende functies en eigenschappen leveren:

  • open():IDataInput - Retourneert het gegevensaanbiederobject waaruit de gegevens voor de bestandsbelofte worden gelezen. De IDataInput-interface moet door dit object worden geïmplementeerd. In geval van asynchrone gegevens moet dit object eveneens de IEventDispatcher-interface implementeren en de benodigde gebeurtenissen verzenden (zie Een asynchrone gegevensaanbieder gebruiken in een bestandsbelofte ).

  • get relativePath():String - Levert het pad, waaronder de bestandsnaam, voor het gemaakte bestand. Het pad wordt omgezet, relatief aan de locatie die door de gebruiker tijdens het slepen en neerzetten is gekozen. Gebruik de constante File.separator als u paden met mappen opgeeft. Op deze manier weet u zeker dat in het pad het juiste scheidingsteken voor het hostbesturingssysteem wordt gebruikt. Als u wilt toestaan dat het pad tijdens runtime wordt ingesteld, voegt u een functie van het type setter toe of gebruikt u een constructorparameter.

  • get isAsync():Boolean - Informeert AIR of het gegevensaanbiederobject gegevens asynchroon of synchroon levert.

  • close():void - Wordt aangeroepen als de gegevens volledig zijn gelezen (of als een fout voorkomt dat er verder wordt gelezen). U kunt deze functie gebruiken voor het opschonen van resources.

  • reportError( e:ErrorEvent ):void - Wordt aangeroepen als er zich bij het lezen van de gegevens een fout voordoet.

Alle IFilePromise-methoden worden aangeroepen bij het slepen en neerzetten van een bestandsbelofte. Doorgaans mogen deze methoden niet rechtstreeks door uw toepassingslogica worden aangeroepen.

Een synchrone gegevensaanbieder gebruiken in een bestandsbelofte

U kunt de IFilePromise-interface het eenvoudigst implementeren met een synchroon gegevensaanbiederobject, zoals een ByteArray of een synchrone FileStream. In het volgende voorbeeld wordt een ByteArray-object gemaakt, gevuld met gegevens en geretourneerd wanneer de methode open() wordt aangeroepen.

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 de praktijk is het nut van synchrone bestandsbeloften beperkt. Als de hoeveelheid gegevens klein is, kunt u net zo gemakkelijk een bestand in een tijdelijke map maken en een normale bestandenlijstarray aan het klembord voor slepen en neerzetten toevoegen. Aan de andere kant, als de hoeveelheid gegevens groot is of als de computer zwaar wordt belast door het genereren van de gegevens, is een lang synchroon proces nodig. Lange synchrone processen kunnen updates van de gebruikersinterface gedurende een aanzienlijke periode blokkeren. Hierdoor kan het lijken alsof uw toepassing niet reageert. Om dit probleem te vermijden, kunt u een asynchrone gegevensaanbieder maken die wordt aangestuurd door een timer.

Een asynchrone gegevensaanbieder gebruiken in een bestandsbelofte

Als u een asynchroon gegevensaanbiederobject gebruikt, moet de eigenschap isAsync van IFilePromise zijn ingesteld op true en moet het object dat wordt geretourneerd door de methode open() de IEventDispatcher-interface implementeren. Tijdens runtime wordt er geluisterd of een aantal alternatieve gebeurtenissen plaatsvinden, zodat verschillende ingebouwde objecten als gegevensaanbieder kunnen worden gebruikt. progress -gebeurtenissen worden bijvoorbeeld verzonden door FileStream- en URLStream-objecten, terwijl socketData -gebeurtenissen worden verzonden door Socket-objecten. Tijdens runtime wordt er geluisterd of al deze objecten de juiste gebeurtenissen verzenden.

Het lezen van gegevens in het gegevensaanbiederobject wordt door de volgende gebeurtenissen aangestuurd:

  • Event.OPEN - Meldt dat de gegevensbron klaar is.

  • ProgressEvent.PROGRESS - Meldt dat de gegevens beschikbaar zijn. Tijdens runtime wordt de hoeveelheid beschikbare gegevens in het gegevensaanbiederobject gelezen.

  • ProgressEvent.SOCKET_DATA - Meldt dat de gegevens beschikbaar zijn. De gebeurtenis socketData wordt verzonden door op sockets gebaseerde objecten. Voor andere typen objecten moet u een progress -gebeurtenis verzenden. (Tijdens runtime wordt er geluisterd wanneer beide gebeurtenissen plaatsvinden, zodat er kan worden bepaald wanneer er gegevens kunnen worden gelezen.)

  • Event.COMPLETE - Meldt dat de gegevens helemaal gelezen zijn.

  • Event.CLOSE - Meldt dat de gegevens helemaal gelezen zijn. (Tijdens runtime wordt er geluisterd wanneer close en complete hiervoor plaatsvinden.)

  • IOErrorEvent.IOERROR - Meldt dat er zich bij het lezen van de gegevens een fout heeft voorgedaan. Het maken van een bestand wordt afgebroken en de methode close() van IFilePromise wordt aangeroepen.

  • SecurityErrorEvent.SECURITY_ERROR - Meldt dat er zich een beveiligingsfout heeft voorgedaan. Het maken van een bestand wordt afgebroken en de methode close() van IFilePromise wordt aangeroepen.

  • HTTPStatusEvent.HTTP_STATUS - Wordt samen met httpResponseStatus gebruikt om ervoor te zorgen dat de beschikbare gegevens de gewenste inhoud representeren en niet een foutbericht (zoals een 404-pagina). Objecten die op het HTTP-protocol zijn gebaseerd, moeten deze gebeurtenis verzenden.

  • HTTPStatusEvent.HTTP_RESPONSE_STATUS - Wordt samen met httpStatus gebruikt om ervoor te zorgen dat de beschikbare gegevens de gewenste inhoud representeren. Objecten die op het HTTP-protocol zijn gebaseerd, moeten deze gebeurtenis verzenden.

De gegevensaanbieder moet deze gebeurtenissen in de volgende volgorde verzenden:

  1. De gebeurtenis open

  2. De gebeurtenis progress of de gebeurtenis socketData

  3. De gebeurtenis complete of de gebeurtenis close

Opmerking: De ingebouwde objecten FileStream, Socket en URLStream verzenden automatisch de juiste gebeurtenissen.

In het volgende voorbeeld wordt een bestandsbelofte gemaakt met een aangepaste asynchrone gegevensaanbieder. De gegevensaanbiederklasse biedt ByteArray uit (voor de ondersteuning voor IDataInput) en implementeert de IEventDispatcher-interface. Bij elke timer-gebeurtenis genereert het object een hoeveelheid gegevens en verzendt het object een progress-gebeurtenis om tijdens runtime te melden dat de gegevens beschikbaar zijn. Als er genoeg gegevens zijn gegenereerd, verzendt het object een complete-gebeurtenis.

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 ); 
    } 
} 
}
Opmerking: Omdat de AsyncDataProvider-klasse in het voorbeeld ByteArray uitbreidt, kan deze klasse niet tevens EventDispatcher uitbreiden. Om de IEventDispatcher-interface te implementeren, gebruikt de klasse een intern EventDispatcher-object en stuurt de IEventDispatcher-methode aanroepen door naar dat interne object. U kunt eventueel ook EventDispatcher uitbreiden en IDataInput implementeren (of beide interfaces implementeren).

De asynchrone IFilePromise-implementatie is bijna identiek aan de synchrone implementatie. De belangrijkste verschillen zijn dat isAsync true retourneert en dat de methode open() een asynchroon gegevensobject retourneert:

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 ); 
        } 
    } 
}