// forked from paq's Flickr!Flickr!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 = "japan"; 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, 90); // ローダ開放 image.unload(); var bmp:Bitmap = new Bitmap(imageBitmap); bmp.x = _imageCount * 90 - (int(_imageCount/10) * 90)*10; bmp.y = int(_imageCount / 10) * 90; 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'; } } forked from: Flickr!Flickr!Flickr!