实现 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。在下面的示例中,创建一个 ByteArray 对象,用数据填充它,并在调用 open() 方法时返回。 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 接口。在每个 timer 事件发生时,对象会生成大量数据,并调度 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 ); } } } |
|