IFilePromise インターフェイスの実装Adobe AIR 2 以降 URLFilePromise オブジェクトを使用してアクセスできないリソースにファイルプロミスを提供するために、IFilePromise インターフェイスをカスタムクラスに実装できます。IFilePromise インターフェイスは、ファイルプロミスがドロップされたときにファイルに書き込まれるデータにアクセスするために AIR ランタイムで使用するメソッドおよびプロパティを定義します。 IFilePromise 実装は、ファイルプロミスにデータを提供する別のオブジェクトを AIR ランタイムに渡します。このオブジェクトは IDataInput インターフェイスを実装する必要があります。AIR ランタイムでは、これを使用してデータを読み取ります。例えば、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 インターフェイスが実装されます。タイマーイベントごとに、オブジェクトではデータのグループを生成し、データが使用可能であることをランタイムに通知する 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 );
}
}
}
|
|