Flickr!Flickr!Flickr!
http://www.libspark.org/wiki/ThreadのFlickrSphereをシンプルにしてFlickrの写真を読み込むだけにした。
*
/**
*
* http://www.libspark.org/wiki/ThreadのFlickrSphereをシンプルにしてFlickrの写真を読み込むだけにした。
*
*/
package
{
import flash.display.Sprite;
import flash.display.Stage;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import org.libspark.thread.EnterFrameThreadExecutor;
import org.libspark.thread.Thread;
[SWF(width=465, height=465, backgroundColor=0x000000, framelate=60)]
public class FlickrTest extends Sprite
{
private var _context:Context = new Context();
public function FlickrTest()
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.LEFT;
addEventListener(Event.ADDED_TO_STAGE, initialize);
}
private function initialize(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, initialize);
_context.stage = stage;
Thread.initialize(new EnterFrameThreadExecutor());
var main:MainThread = new MainThread(_context);
main.start();
}
}
}
/*=============================================================================================
*///===========================================================================================
import flash.display.Bitmap;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.display.Stage;
import flash.display.Loader;
import flash.display.BitmapData;
import flash.events.Event;
import flash.net.URLRequest;
import flash.net.URLVariables;
import flash.system.LoaderContext;
import flash.geom.Matrix;
import org.libspark.thread.IMonitor;
import org.libspark.thread.Monitor;
import org.libspark.thread.threads.display.LoaderThread;
import org.libspark.thread.EnterFrameThreadExecutor;
import org.libspark.thread.Thread;
import org.libspark.thread.threads.net.URLLoaderThread;
import org.libspark.thread.utils.ParallelExecutor;
import org.libspark.thread.threads.tweener.TweenerThread;
/***********************************************************************************************
* MainThread - メイン
*/
internal class MainThread extends Thread
{
/**
* @param context コンテキスト
*/
public function MainThread(context:Context)
{
_context = context;
}
private var _context:Context;
private var _searchFlickr:SearchFlickrPhotoThread;
//検索するキーワード
private const KEYWORD:String = "HDR";
override protected function run():void
{
next(seach);
}
private function seach():void
{
_searchFlickr = new SearchFlickrPhotoThread(KEYWORD);
_searchFlickr.start();
_searchFlickr.join();
next(seachComplete);
}
private function seachComplete():void
{
var flickrphotos:Array = _searchFlickr.photos;
var displayFlickr:DisplayFlickrPhotoThread = new DisplayFlickrPhotoThread(_context, flickrphotos);
displayFlickr.start();
}
}
/***********************************************************************************************
* Context - Thread内で必要なものを保有するクラス
*/
internal class Context
{
public var stage:Stage;
}
/***********************************************************************************************
* DisplayFlickrPhotoThread - 写真を表示
*/
internal class DisplayFlickrPhotoThread extends Thread
{
/**
* @param context コンテキスト
* @param photos 表示する FlickrPhoto の配列
*/
public function DisplayFlickrPhotoThread(context:Context, photos:Array)
{
_context = context;
_photos = photos;
_tempMatrix = new Matrix();
_imageCount = 0;
}
private var _context:Context;
private var _photos:Array;
private var _queue:PhotoImageQueue;
private var _loaders:ParallelExecutor;
private var _imageBitmaps:Array;
private var _imageCount:uint;
private var _tempMatrix:Matrix;
private var _tweens:Array;
override protected function run():void
{
_imageBitmaps = [];
// ロードされた写真を受け取るためのキュー
_queue = new PhotoImageQueue();
// 写真イメージをロードするためのスレッドを 4 つ作る
_loaders = new ParallelExecutor();
_loaders.addThread(new LoadFlickrPhotoImagesThread(_photos, _queue));
_loaders.addThread(new LoadFlickrPhotoImagesThread(_photos, _queue));
_loaders.addThread(new LoadFlickrPhotoImagesThread(_photos, _queue));
_loaders.addThread(new LoadFlickrPhotoImagesThread(_photos, _queue));
// ロード開始
_loaders.start();
// 写真表示
displayPhoto();
}
private function displayPhoto():void
{
// 読み込まれている写真が無ければ待つ
if (_queue.checkPoll()) {
next(displayPhoto);
interrupted(displayPhotoInterrupted);
return;
}
// 割り込まれていたら displayInterrupted へ
if (checkInterrupted()) {
displayPhotoInterrupted();
return;
}
// 写真イメージを取得
var image:Loader = _queue.poll();
// BitmapData に転写
var imageBitmap:BitmapData = getBitmapData(image, 47);
// ローダ開放
image.unload();
var bmp:Bitmap = new Bitmap(imageBitmap);
bmp.x = _imageCount * 47 - (int(_imageCount/10) * 47)*10;
bmp.y = int(_imageCount / 10) * 47;
bmp.scaleX = bmp.scaleY = 1;
_context.stage.addChild(bmp);
_imageCount++;
_imageBitmaps.push(imageBitmap);
// 次の写真イメージへ
next(displayPhoto);
}
private function getBitmapData(image:Loader, size:uint):BitmapData
{
// BitmapData
var bitmapData:BitmapData = new BitmapData(size, size, false);
// 指定されたサイズに縮小して描画
_tempMatrix.identity();
_tempMatrix.scale(size / image.contentLoaderInfo.width, size / image.contentLoaderInfo.height);
bitmapData.draw(image.content, _tempMatrix);
return bitmapData;
}
private function displayPhotoInterrupted():void
{
// 全てのロードをキャンセル
_loaders.interrupt();
_loaders = null;
}
override protected function finalize():void
{
// BitmapData 開放
for each (var bitmap:BitmapData in _imageBitmaps) {
bitmap.dispose();
}
_imageBitmaps = null;
}
}
/***********************************************************************************************
* LoadFlickrPhotoImagesThread - FlickPhoto のイメージを読み込んで PhotoImageQueue に追加
*/
internal class LoadFlickrPhotoImagesThread extends Thread
{
/**
* @param photos 読み込む FlickrPhoto の配列
* @param queue 読み込んだイメージを格納する PhotoImageQueue
*/
public function LoadFlickrPhotoImagesThread(photos:Array, queue:PhotoImageQueue)
{
_photos = photos;
_queue = queue;
}
private var _photos:Array;
private var _queue:PhotoImageQueue;
private var _loader:LoaderThread;
override protected function run():void
{
// もう読み込む写真が無ければ終了
if (_photos.length == 0) {
return;
}
// 読み込む写真
var photo:FlickrPhoto = FlickrPhoto(_photos.shift());
// ロード開始
_loader = new LoaderThread(new URLRequest(photo.smallSquareImageURL), new LoaderContext(true));
_loader.start();
_loader.join();
// 完了したら loadComplete
next(loadComplete);
// 割り込まれたら loadInterrupted
interrupted(loadInterrupted);
// エラーが起きたら loadError
error(Error, loadError);
}
private function loadComplete():void
{
// 読み込んだ写真をキューに追加
_queue.offer(_loader.loader);
// LoaderThread 破棄
_loader = null;
// 次を読み込む
run();
}
private function loadInterrupted():void
{
// LoaderThread にも割り込みをかけて終了
_loader.interrupt();
_loader = null;
}
private function loadError(e:Error, t:Thread):void
{
// 写真イメージの読み込みでエラーが起きた際には無視する
_loader = null;
// 何事も無かったかのように次へ
run();
}
}
/***********************************************************************************************
* PhotoImageQueue - ロードした写真イメージをストックするためのキュー
*/
internal class PhotoImageQueue
{
public function PhotoImageQueue()
{
_queue = [];
_monitor = new Monitor();
}
private var _queue:Array;
private var _monitor:IMonitor;
/**
* キューが空であれば true、そうでなければ false を返します.
*/
public function get isEmpty():Boolean
{
return _queue.length == 0;
}
/**
* キューに指定されたイメージを追加します.
*
* @param image 追加するイメージ
*/
public function offer(image:Loader):void
{
// キューに追加
_queue.push(image);
// checkPoll でイメージを取得可能になるまで待機しているスレッドを起こす
_monitor.notifyAll();
}
/**
* キューからイメージを取得可能かどうかをチェックし、可能でなければ取得可能になるまでスレッドを待機させます.
*
* @return スレッドが待機する場合に true、そうでなければ false
*/
public function checkPoll():Boolean
{
// キューが空であれば
if (isEmpty) {
// スレッドを待機させる
_monitor.wait();
return true;
}
return false;
}
/**
* キューからイメージを取得します.
*
* @return イメージ
*/
public function poll():Loader
{
// キューから取得
return _queue.shift();
}
}
/***********************************************************************************************
* SearchFlickrPhotoThread - Flickrから写真を検索。
*/
internal class SearchFlickrPhotoThread extends Thread
{
private static const REST_URL:String = 'http://api.flickr.com/services/rest/';
private static const REST_METHOD_NAME:String = 'flickr.photos.search';
public const FLICKR_APIKEY:String = 'cfc81e109140b97151488162030ced4b';
/**
* @param keyword 検索キーワード
*/
public function SearchFlickrPhotoThread(keyword:String)
{
_keyword = keyword;
_photos = [];
}
private var _keyword:String;
private var _loader:URLLoaderThread;
private var _photos:Array;
/**
* 読み込んだ写真の FlickrPhoto の配列を返します.
*/
public function get photos():Array
{
return _photos;
}
/**
* API を呼び出すための URLRequest を生成して返します.
*
* @return URLRequest
* @private
*/
private function createURLRequest():URLRequest
{
var req:URLRequest = new URLRequest(REST_URL);
req.data = createURLVariables();
return req;
}
/**
* API を呼び出すための URLVariables を生成して返します.
*
* @return URLVariables
* @private
*/
private function createURLVariables():URLVariables
{
var val:URLVariables = new URLVariables();
val['api_key'] = FLICKR_APIKEY;
val['method'] = REST_METHOD_NAME;
val['text'] = _keyword;
return val;
}
override protected function run():void
{
_loader = new URLLoaderThread(createURLRequest());
_loader.start();
_loader.join();
// 完了
next(loadComplete);
// 割り込み
interrupted(loadInterrupted);
}
private function loadInterrupted():void
{
// URLLoaderThread に割り込み
_loader.interrupt();
_loader = null;
}
private function loadComplete():void
{
// XML 取得
var xml:XML = XML(_loader.loader.data);
// REST レスポンスが正常であれば
if ('@stat' in xml && String(xml.@stat) == 'ok') {
_photos.length = 0;
// 写真データを FlickrPhoto クラスに詰め込んで配列に入れる
for each (var photoXML:XML in xml.photos.photo) {
var photo:FlickrPhoto = new FlickrPhoto();
photo.id = String(photoXML.@id);
photo.secret = String(photoXML.@secret);
photo.serverId = String(photoXML.@server);
photo.farmId = String(photoXML.@farm);
_photos.push(photo);
}
}
else {
// 正常でなければエラー
throw new Error('flickr.photos.search');
}
}
}
/***********************************************************************************************
* FlickrPhoto - Flickr の写真データのモデルクラス
*/
internal class FlickrPhoto
{
private var _id:String = '';
private var _secret:String = '';
private var _serverId:String = '';
private var _farmId:String = '';
public function get id():String
{
return _id;
}
public function set id(value:String):void
{
_id = value;
}
public function get secret():String
{
return _secret;
}
public function set secret(value:String):void
{
_secret = value;
}
public function get serverId():String
{
return _serverId;
}
public function set serverId(value:String):void
{
_serverId = value;
}
public function get farmId():String
{
return _farmId;
}
public function set farmId(value:String):void
{
_farmId = value;
}
public function get smallSquareImageURL():String
{
return 'http://farm' + farmId + '.static.flickr.com/' + serverId + '/' + id + '_' + secret + '_s.jpg';
}
}