BulkLoaderにはまった --その2--
2008/03/13 10:16 更新
ロードされる側のBaseクラスのインスタンスが生成されるかどうか(コンストラクタが呼び出されているか)について記載していなかったので追記。 結論から言うと、ロードされる側のBaseクラスは、コンストラクタが呼び出されていませんでした。 実行側Rootをnew→実行側Baseをnew→ロード側Rectをnew→実行側Baseをnew 今回の検証で、外部swfをロードする際に注意すべき事として、下記が挙げられる。 その他にもあれば是非とも教えてください! ・同じクラス名は使用しない。 ・ロードされる側のドキュメントクラスではstageを参照出来ない。
前回の続きのお話です。
続きと言っても、はまった原因はFlashの仕様的な話です。
そもそも、berianが外部swfをロードするという事を今まで経験していなかった事が原因と思われる。。
以下、使用したBulkLoaderのリビジョンは186(2008/03/12現在の最新)です。
下記がロードされる側のコード。
Rect.as(ドキュメントクラス)
package { import flash.display.MovieClip; public class Rect extends MovieClip { public function Rect():void { addChild(new Base()); } } }
Base.as
package { import flash.display.Sprite; public class Base extends Sprite { public function Base():void { graphics.beginFill(0x000000); graphics.drawRect(0, 0, 300, 300); graphics.endFill(); } } }
単純に四角を描画しているだけです。
これをrect.swfとしてコンパイルして使用。
ちなみに、ドキュメントクラスRect.asがSpriteではなく、MovieClipを継承しているのは、BulkLoaderのgetMovieClipメソッドを使用して取得する事を想定しているためです。
次に、rect.swfをロードする側のコード
Root.as(ドキュメントクラス)
package { import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageQuality; public class Root extends Sprite { public function Root():void { stage.scaleMode = "noScale"; stage.align = StageAlign.TOP_LEFT; stage.quality = StageQuality.HIGH; addChild(new Base()); } } }
Base.as
package { import flash.display.Sprite; import br.com.stimuli.loading.BulkLoader; import br.com.stimuli.loading.BulkProgressEvent; public class Base extends Sprite { public function Base():void { var bulkLoader:BulkLoader = new BulkLoader("Bulk Test"); bulkLoader.add('rect.swf'); bulkLoader.addEventListener(BulkLoader.COMPLETE, completeHandler); bulkLoader.start(); } private function completeHandler(e:BulkProgressEvent):void { var bulkLoader:BulkLoader = BulkLoader.getLoader("Bulk Test"); addChild(bulkLoader.getMovieClip('rect.swf')); } } }
単純にrect.swfをロードしてaddChildしているだけです。
これをRoot.swfとしてコンパイルして実行すると・・
Error: BulkLoader with name'Bulk Test' has already been created. at br.com.stimuli.loading::BulkLoader() at Base() at Rect()
"Bulk Test"という名前でBulkLoaderインスタンスは既に作成されています!!(怒)・・と
いやいや・・ワタクシ2回もBulkLoaderコンストラクタ呼んでませんから・・
怒られる筋合いありませんから・・
デバッグしてみると、どうやらstartメソッドを実行したタイミングで、BulkLoaderコンストラクタがもう一度呼び出されているみたい。。
おかしいなぁ。。と思って、エラーメッセージをよーく見てみると、、
at Base() at Rect()
どうもエラー発生箇所がロードされる側のswfのようです。
なぜ・・!?!?!?
もうパニックですwww
ロードされる側のBaseクラスからBulkLoaderコンストラクタが呼び出されている・・
・・・
ここでberian、やっと閃いた!!
実行するswf(Root.swf)にも、ロードされるswf(rect.swf)にもBaseクラスが存在する。
そして実行するswfのBaseクラスで、実際はBulkLoaderコンストラクタを呼び出している。
もしかして・・!!
って事で、実行するswf(Root.swf)のBaseクラスをBulkクラスにクラス名を変更。
Root.as(ドキュメントクラス)
package { import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageQuality; public class Root extends Sprite { public function Root():void { stage.scaleMode = "noScale"; stage.align = StageAlign.TOP_LEFT; stage.quality = StageQuality.HIGH; addChild(new Bulk()); } } }
Bulk.as
package { import flash.display.Sprite; import br.com.stimuli.loading.BulkLoader; import br.com.stimuli.loading.BulkProgressEvent; public class Bulk extends Sprite { public function Bulk():void { var bulkLoader:BulkLoader = new BulkLoader("Bulk Test"); bulkLoader.add('rect.swf'); bulkLoader.addEventListener(BulkLoader.COMPLETE, completeHandler); bulkLoader.start(); } private function completeHandler(e:BulkProgressEvent):void { var bulkLoader:BulkLoader = BulkLoader.getLoader("Bulk Test"); addChild(bulkLoader.getMovieClip('rect.swf')); } } }
処理は何も変えずにクラス名のみ変更してあります。
これをRoot.swfとしてコンパイルし、実行すると・・
おめでとーございまーす!!!
結局、何がどう悪さをしていたのかをまとめると。
【前提条件】
・Root.swfにもrect.swfにもBaseクラスが存在した。
・BulkLoaderのインスタンスを生成しているのはRoot.swfのBaseクラス。
【実際に行われた処理の流れ】
・Root.swfでBaseクラスのインスタンスが生成される。
・BaseクラスでBulkLoaderクラスのインスタンスが生成される。
・BulkLoaderインスタンスのstartメソッドを実行する。
・rect.swfがロードされる。
・rect.swfが実行され、rect.swfのRectクラス→rect.swfのBaseクラスのインスタンスが順に生成される・・
と思いきや、Root.swfのBaseクラスのインスタンスがここでもう一度生成されてしまう。
これによって、結果的にBulkLoaderクラスのコンストラクタが2回呼ばれてしまったという事だった。
いやー、、この挙動は知らなかったなぁ。。
外部swfにロードする側と同じクラス名を使ってはいけないって事か。
完全に独立して動くものかと思ってたが。。
まぁ、勉強になったという事で!!