Home > flex > Flexで画像のロードが終わるまで待機したい(Sleepが無い!!)

Flexで画像のロードが終わるまで待機したい(Sleepが無い!!)

どうも、うしねずみです。
Flexでの画像のロードについて、悩んだので書いてみます。どうやらFlexにはSleep関数が無いようで、そのせいで色々悩みました。まずは、画像をロードする方法をまとめてみます。

方法その1: LoaderをそのままaddChildする

例えばロードした表示するだけの時は以下のように書きます。

loaderをuicにaddChildしたものをaddChildすれば画像が表示されるというちょっと不可思議な感じ。

方法その2: COMPLETEイベントのリスナーを登録しておく

方法その1だと、画像を表示するだけなら出来ましたが、画像を扱ってどうにかしたいときは困ります。そういう時は以下の方法。

4行目でloadComplete関数をロード完了時のイベントリスナに登録しています。よって、画像の読み込みが終わるとloadComplete関数に制御が飛んで、その中で画像を使った処理ができます。test関数はロードが完了する前にリターンされます。よってtest関数を呼んだ側の処理が画像のロードの間待たされるわけではありません。

さて、ここで問題が

実はこの「ロードが終わる前に制御が戻る」という性質が厄介だったりするのです。最近画像のラッパーを作っていたのですが、その時に「画像のロードが終了するまで呼び出し側の実行を待機したい」ということがありました。例えば以下のようなラッパーを作ったとします。

このクラスは、画像のアドレスを渡してnewすると、コンストラクタ内で画像をロードしておいてくれるクラスです。これだけだとアドレスと画像を持っているだけですが、他にもこの画像に関する様々な情報をまとめて持たせるためのクラスです。
さて、このクラスは例えば以下のように使われます。

ここで問題が生じるのです。MyImageWrapperのコンストラクタはロード処理を開始するだけで、ロードが終わるまで待ちません。なのでまだMyImageWrapperのloadCompleteが呼ばれないうちに制御が返ってきます。すると2行目でまだmyImage.imageDataはnullなので、「nullはaddChildできません」というエラーになるのです。
じゃー答えは簡単。imageDataがnullじゃなくなるまで待てばいいんだな、と思って次のように書き変えました。

ところが、このソースを実行してみると、永久にloadCompleteが呼ばれず、5行目にたどりつくことができません。Flex(Flash)の中で「CPUが空き状態になるまでloadCompleteの実行は待機する」という仕様になっているのでしょうか。

じゃあ空ループじゃなくてSleepすればいいんだな。と思って調べたのですが、どうやらFlexにはSleepが無い模様。
さて、困った。

Timerを使って実装することもできなくはないです。以下のようになります。

タイマは、一定時間ごとに登録したリスナを呼んでくれます。ここでは無名関数をその場で定義して登録しています。つまりこのタイマは100msごとに画像のロードが終わってるかどうかをチェックして、もし終わってたらaddChildを済ませて、自分自身(タイマ)を止めてくれます。
しかしこれはこれでなんか面倒だしすっきりしません。また、timer.start()のところで実行が待機するわけではないので別のところで画像データを使いたくなったときに既に画像のロードが終わっている保証がありません。

例えばユーザには「画像ロードボタン」と「画像編集ボタン」が提示されているとします。「画像ロードボタン」はユーザが指定したURLから画像をロードしてくるボタンです。「画像編集ボタン」はロードした画像に何か編集を加えるボタンです(モノクロに変換するなど、何でもよい)。仮にタイマを使っても、「画像ロードボタン」を押したあとロードが完了する前に制御がユーザに戻ってしまいます。その後すぐに「画像編集ボタン」を押されると、「画像編集ボタン」のイベントハンドラは既に画像が読み込まれていることを期待して読みに来ますが、実際は画像データはありません。

結局、対策としては、画像がロード済みかどうか(null)じゃないかどうか、使う前に毎回チェックして、ロードが済んでいなかったら何もしないっていうこと。それしかないのかなー。
なんとかSleep的な処理ができないかなーと思って疑似Threadライブラリ(そうめん?)なんかも試してみた。Threadが終了するまで待つことができるjoin関数が使えるかと思ったけど、Threadの終了を待てるのはThreadだけのようで、Threadではない実行部分で何かの処理を待機することはできない模様。
完全に手詰まりです。

ところで、Sleepが無い理由を自分なりに考えてみた。
Flexは基本的にイベント駆動型のアプリを作るためにあるはずなので、一つのイベントが全体をSleepさせるような処理を書くべきではない、ということなのだと思う。
でも、なんか、かゆい所に手が届かないむずむずというか、、、初めてSchemeを触った時に「破壊的代入を行わないプログラミング」が難しいパズルのようでどうしても頭に入ってこなかった時のような気持ち悪さ。
まー、修行が足りないってことですかね。

Comments:2

tan_go238 10-03-05 (金) 13:16

この場合、Timerではなく、myImage に対して addEventListener しておいて MyImageWrapper#loadComplete時に dispatchEvent を発生させておけばいいと思います。

usinezumi 10-03-24 (水) 12:00

tan_go238さん、コメントありがとうございます。それから、最近身の回りが忙しかっため、返信が遅れてすいません。
たしかに、画像に対してどういう処理をするか決まっている場合であれば、リスナー登録しておいてロード完了時に処理してもらうことで対処できそうです。
私の場合は、画像に加える処理をユーザーが後から決定できるような仕様にしたいと考えています。例えば、指定したURLからロードした画像にお絵かきできるアプリだとすると、まずユーザーがURLを指定して「ロードボタン」を押します。そのあとペンで書き込みます(←これが画像に加える処理)。この場合「ペンで書き込まれた」というイベントのハンドラは画像に変更を加える処理をしたいのですが、その時点でまだ画像のロードが完了してない可能性があります。本来なら「画像のロードが終わるまで一時待機」してから処理を済ませたいのですが、Sleepが無い(whileループもダメ)ので何もせずにreturnするしかないといった問題です。
コマンドパターンを使って、画像が無い時に受け付けた処理をキューにためておくなどの細工があれば実装できそうです。
私も勉強不足ですので、勘違いなどあるかもですが。。。

Comment Form
Remember personal info

Trackbacks:0

Trackback URL for this entry
http://www.usinezumi.com/blog/2009/12/07/227/trackback/
Listed below are links to weblogs that reference
Flexで画像のロードが終わるまで待機したい(Sleepが無い!!) from うしねずみの技術メモ

Home > flex > Flexで画像のロードが終わるまで待機したい(Sleepが無い!!)

Search
Feeds

Return to page top