Implementera gränssnittet IFilePromise

Adobe AIR 2 och senare

Om du vill ange fillöften för resurser som inte kan kommas åt med hjälp av ett URLFilePromise-objekt kan du implementera gränssnittet IFilePromise i en anpassad klass. Gränssnittet IFilePromise anger vilka metoder och egenskaper som används av AIR-körningen för att komma åt data som ska skrivas till en fil när fillöften släpps.

En IFilePromise-implementering skickar ett annat objekt till AIR-körningen som tillhandahåller data för fillöftet. Objektet måste implementera gränssnittet IDataInput som används av AIR-körningen för att läsa data. Klassen URLFilePromise som implementerar IFilePromise använder till exempel ett URLStream-objekt som dataleverantör.

I AIR kan data läsas synkront eller asynkront. IFilePromise-implementeringen rapporterar vilket åtkomstläge som stöds genom att returnera korrekt värde i egenskapen isAsync . Om asynkron dataåtkomst tillhandahålls måste dataleverantörsobjektet implementera gränssnittet IEventDispatcher och skicka nödvändiga händelser som open , progress och complete .

Som dataleverantör för ett fillöfte kan du använda en anpassad klass, eller någon av följande inbyggda klasser:

  • ByteArray (synkron)

  • FileStream (synkron eller asynkron)

  • Socket (asynkron)

  • URLStream (asynkron)

Om du vill implementera gränssnittet IFilePromise måste du ange kod för följande funktioner och egenskaper:

  • open():IDataInput – Returnerar det dataleverantörsobjekt från vilket data läses för fillöftet. Objektet måste implementera gränssnittet IDataInput. Om data tillhandahålls asynkront måste objektet också implementera gränssnittet IEventDispatcher och skicka nödvändiga händelser (se Använda en asynkron dataleverantör i ett fillöfte ).

  • get relativePath():String – Anger sökvägen, inklusive filnamn, för den skapade filen. Sökvägen skapas i relation till den plats där användaren väljer att släppa objektet i åtgärden dra och släpp. Om du vill vara säker på att rätt avgränsningstecken för värdoperativsystemet används i sökvägen använder du konstanten File.separator när du anger sökvägar som innehåller kataloger. Du kan lägga till en inställningsmetod eller använda en konstruktorparameter för att tillåta att sökvägen ställs in under körning.

  • get isAsync():Boolean – Informerar AIR-körningen om huruvida dataleverantörsobjektet tillhandahåller data asynkront eller synkront.

  • close():void – Anropas av körningen när läsningen av data är helt slutförd (eller ett fel förhindrar fortsatt läsning). Du kan använda den här funktionen för att rensa resurser.

  • reportError( e:ErrorEvent ):void – Anropas av körningen när ett fel inträffar vid läsningen av data.

Alla IFilePromise-metoder anropas av körningen under en dra och släpp-åtgärd där fillöftet används. Programlogiken skulle normalt inte anropa någon av dessa metoder direkt.

Använda en synkron dataleverantör i ett fillöfte

Det enklaste sättet att implementera gränssnittet IFilePromise är genom att använda ett synkront dataleverantörsobjekt, till exempel ett ByteArray eller ett synkront FileStream. I följande exempel skapas ett ByteArray-objekt, fylls med data och returneras när metoden open() anropas.

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

I praktiken är användbarheten för synkrona fillöften begränsad. Om mängden data är liten kan du lika enkelt skapa en fil i en tillfällig katalog och lägga till en vanlig fillistearray till Urklipp för dra och släpp. Det krävs däremot en lång synkron process om mängden data är stor, eller om det är resurskrävande att skapa dessa data. Långa synkrona processer kan blockera uppdateringar av användargränssnittet under märkbart lång tid och få det att verka som att programmet inte svarar. Om du vill undvika det här problemet kan du skapa en asynkron dataleverantör som styrs av en timer.

Använda en asynkron dataleverantör i ett fillöfte

När du använder ett asynkront dataleverantörsobjekt måste IFilePromise-egenskapen isAsync vara true och objektet som returneras av metoden open() måste implementera gränssnittet IEventDispatcher. Körningen lyssnar efter flera alternativa händelser så att olika inbyggda objekt kan användas som dataleverantör. Till exempel skickas progress -händelser av FileStream- och URLStream-objekt, medan socketData -händelser skickas av Socket-objekt. Körningen lyssnar efter lämpliga händelser från alla dessa objekt.

Följande händelser styr processen att läsa data från dataleverantörsobjektet:

  • Event.OPEN – Informerar körningen om att datakällan är färdig.

  • ProgressEvent.PROGRESS – Informerar körningen om att det finns tillgängliga data. Körningen kommer att läsa mängden befintliga data från dataleverantörsobjektet.

  • ProgressEvent.SOCKET_DATA – Informerar körningen om att det finns tillgängliga data. Händelsen socketData skickas av socket-baserade objekt. För andra objekttyper bör du skicka en progress -händelse. (Körningen lyssnar efter båda objekten för att avgöra vilka data som kan läsas.)

  • Event.COMPLETE – Informerar körningen om att alla data har lästs.

  • Event.CLOSE – Informerar körningen om att alla data har lästs. (Körningen lyssnar av den här anledningen efter både close och complete .)

  • IOErrorEvent.IOERROR – Informerar körningen om att ett fel uppstod när data lästes. Körningen avbryter skapandet av filen och anropar IFilePromise-metoden close() .

  • SecurityErrorEvent.SECURITY_ERROR – Informerar körningen om att ett säkerhetsfel har inträffat. Körningen avbryter skapandet av filen och anropar IFilePromise-metoden close() .

  • HTTPStatusEvent.HTTP_STATUS – Används av körningen tillsammans med httpResponseStatus för att säkerställa att tillgängliga data representerar önskat innehåll, och inte något felmeddelande (till exempel en 404-sida). Objekt som utgår från HTTP-protokollet bör skicka den här händelsen.

  • HTTPStatusEvent.HTTP_RESPONSE_STATUS – Används av körningen tillsammans med httpStatus för att säkerställa att tillgängliga data representerar önskat innehåll. Objekt som utgår från HTTP-protokollet bör skicka den här händelsen.

Dataleverantören bör skicka de här händelserna i följande sekvens:

  1. open -händelse

  2. progress - eller socketData -händelser

  3. complete - eller close -händelse

Obs! De inbyggda objekten FileStream, Socket, och URLStream skickar automatiskt de rätta händelserna.

I följande exempel skapas ett fillöfte med hjälp av en anpassad, asynkron dataleverantör. Dataleverantörsklassen utökar ByteArray-objektet (för IDataInput-stöd) och implementerar gränssnittet IEventDispatcher. Vid varje timerhändelse genererar objektet en mängd data och skickar en förloppshändelse för att informera körningen om att dessa data finns tillgängliga. När en tillräckligt stor mängd data har producerats skickar objektet en slutförandehändelse.

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 ); 
    } 
} 
}
Obs! Eftersom klassen AsyncDataProvider i exemplet utökar ByteArray, kan den inte också utöka EventDispatcher. Klassen använder ett internt EventDispatcher-objekt för att implementera gränssnittet IEventDispatcher och vidarebefordrar IEventDispatcher-metodanropen till det interna objektet. Du bör också utöka EventDispatcher och implementera IDataInput (eller implementera båda gränssnitten).

Den asynkrona implementeringen av IFilePromise är nästan identisk med den synkrona implementeringen. De viktigaste skillnaderna är att isAsync returnerar true och att metoden open() returnerar ett asynkront dataobjekt:

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