IFilePromise 인터페이스 구현Adobe AIR 2 이상 URLFilePromise 객체를 사용하여 액세스할 수 없는 리소스에 대해 파일 프로미스를 제공하려면 사용자 정의 클래스에서 IFilePromise 인터페이스를 구현할 수 있습니다. IFilePromise 인터페이스는 파일 프로미스가 드롭된 후 파일에 기록할 데이터에 액세스하기 위해 AIR 런타임에서 사용되는 메서드 및 속성을 정의합니다. IFilePromise 구현은 AIR 런타임에 파일 프로미스에 대한 데이터를 제공하는 또 다른 객체를 전달합니다. 이 객체는 AIR 런타임이 데이터를 읽기 위해 사용하는 IDataInput 인터페이스를 구현해야 합니다. 예를 들어 IFilePromise를 구현하는 URLFilePromise 클래스는 URLStream 객체를 데이터 공급자로 사용합니다. AIR는 데이터를 동기적 또는 비동기적으로 읽을 수 있습니다. IFilePromise 구현은 isAsync 속성에 적합한 값을 반환하여 지원되는 액세스 모드를 보고합니다. 비동기 데이터 액세스가 제공되는 경우 데이터 공급자 객체는 IEventDispatcher 인터페이스를 구현하고 open, progress 및 complete와 같은 필요한 이벤트를 전달해야 합니다. 사용자 정의 클래스 또는 다음과 같은 기본 제공 클래스 중 하나를 파일 프로미스에 대한 데이터 공급자로 사용할 수 있습니다.
IFilePromise 인터페이스를 구현하려면 다음 함수 및 속성에 대한 코드를 제공해야 합니다.
모든 IFilePromise 메서드는 파일 프로미스와 관련된 드래그 앤 드롭 작업 중에 런타임에서 호출됩니다. 일반적으로 응용 프로그램 논리에서는 이러한 메서드를 직접 호출하지 않아야 합니다. 파일 프로미스에서 동기 데이터 공급자 사용IFilePromise 인터페이스를 구현하는 가장 간단한 방법은 ByteArray 또는 동기 FileStream과 같은 동기 데이터 공급자 객체를 사용하는 것입니다. 다음 예제에서는 open() 메서드가 호출될 때 ByteArray 객체가 만들어지고 데이터로 채워지며 반환됩니다. 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 ); } } } 실제로, 동기 파일 프로미스는 사용이 제한적입니다. 데이터 양이 적은 경우에는 임시 디렉토리에 파일을 만들어서 드래그 앤 드롭 클립보드에 일반적인 파일 목록 배열을 추가하면 간편합니다. 반면에 데이터 양이 많거나 데이터 생성의 계산이 복잡한 경우 긴 동기 프로세스가 필요합니다. 긴 동기 프로세스는 상당한 시간 동안 UI 업데이트를 차단하여 응용 프로그램이 응답하지 않는 것처럼 보이게 만들 수 있습니다. 이러한 문제를 방지하기 위해서는 타이머로 구동되는 비동기 데이터 공급자를 만들 수 있습니다. 파일 프로미스에서 비동기 데이터 공급자 사용비동기 데이터 공급자 객체를 사용하는 경우에는 IFilePromise isAsync 속성이 true여야 하며 open() 메서드로 반환되는 객체에서 IEventDispatcher 인터페이스를 구현해야 합니다. 런타임에서는 여러 기본 제공 객체를 데이터 공급자로 사용할 수 있도록 몇 가지 대체 이벤트를 수신합니다. 예를 들어 progress 이벤트는 FileStream 및 URLStream 객체에 의해 전달되지만 socketData 이벤트는 Socket 객체에 의해 전달됩니다. 런타임에서는 이러한 모든 객체로부터 적합한 이벤트를 수신합니다. 다음 이벤트는 데이터 공급자 객체에서 데이터를 읽는 프로세스를 구동합니다.
데이터 공급자는 다음과 같은 순서로 이러한 이벤트를 전달해야 합니다.
참고: 기본 제공 객체 FileStream, Socket 및 URLStream은 적합한 이벤트를 자동으로 전달합니다.
다음 예제에서는 사용자 정의 비동기 데이터 공급자를 사용하여 파일 프로미스를 만듭니다. 데이터 공급자 클래스는 ByteArray(IDataInput 지원)를 확장하고 IEventDispatcher 인터페이스를 구현합니다. 각 타이머 이벤트에서 객체는 데이터 청크를 생성하고 데이터를 사용할 수 있음을 런타임에 알리기 위해 progress 이벤트를 전달합니다. 충분한 데이터가 생성되면 객체가 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 ); } } } 참고: 예제에서 AsyncDataProvider 클래스는 ByteArray를 확장하므로 EventDispatcher도 확장할 수 없습니다. IEventDispatcher 인터페이스를 구현하기 위해 클래스에서는 내부 EventDispatcher 객체를 사용하고 IEventDispatcher 메서드 호출을 해당 내부 객체에 전달합니다. 또한 EventDispatcher를 확장하고 IDataInput(또는 두 인터페이스 모두)를 구현할 수 있습니다.
비동기 IFilePromise 구현은 동기 구현과 거의 동일합니다. 주요 차이점은 isAsync는 true를 반환하고, open() 메서드는 비동기 데이터 객체를 반환한다는 것입니다. 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 ); } } } |
|