[AS]Flash(AS3)におけるローディングバーが正常に動作しないときのひとつの理由

すげぇ、はまったのでメモしておきます。

まずは状況説明

  • テスト環境(heteml)では何の問題もなくローディングバーが表示されていた。
  • 本番環境(海外のよくわからんサーバー)にアップするとローディングバーの挙動がわけわからんようになった。
  • FFだと常に100%表示で、IEとかChromeだと常に0%表示になってしまう。

数日悩んだ後、飲み会の席で某HIGE先生に相談したら1分で解決してくれました。

「サーバーがHttpヘッダにContentLength返さない仕様だとbytesTotalがおかしくなるよ」
「ブラウザごとで解釈が違うと思うよ」


サーバー側がContentLengthを返さないのが原因かもとのこと。
対策としては、あらかじめ読み込むファイルのサイズがわかってるなら、bytesTotalを使わずにバイト数を決め打ちで入力しておく。
ファイルサイズがわからんのなら、いっそ%表示のないポンデリングローダーにしちゃう。
そんな感じでOK。


ちなみに実はAS3のリファレンスにも書いてありました。

ダウンロードデータの合計バイト数を示します。このプロパティは、ロード操作の進行中は 0 を格納し、操作が完了した時点で設定されます。また、Content-Length ヘッダーがない場合、bytesTotal の値が不確定になります。

URLLoaderのbytesTotalの項目に書かれています。
がしかし、LoaderInfoのbytesTotalの項目にはこれ書いてないんですよね。。。
今回はswfの読み込みで発生したので、LoaderInfoのbytesTotalも同様の現象が起きますよ、ということ。
なんともいやらしい罠でした。

[AS]ProgressionのPreloaderで”「Error #2044: ハンドルされていない ioError : text=Error #2036: 読み込みが未完了です。 URL: index.swf?”となってしまう場合の対処方法

ProgressionでPreloader.asからindex.swfを読み込むときにこんなエラーダイアログに悩まされてました。

どういうときにこのエラーになるかというと、Preloader.swfがindex.swfの読みこみが終わらないうちに、ブラウザを閉じてしまうとこうなります。
index.swfが重い場合、「ローディング長いからもう観なくていいや」ってブラウザ落とすと上記ダイアログで固まるんですね。
最高にうざい状態です。

で、エラーとしては、IOErrorってわかってるので、そこのエラー処理を書いてあげればいいんですけど、読み込みの処理はPreloader.asの親クラスに書いてあるので、どのオブジェクトに対して、IOErrorのハンドリングをすればいいのかわからなかったのですが、ついに重い腰をあげて親クラスの中身を覗いてみたら、5分で解決したというオチです。

結論としては、こんな感じ。

//Preloader.asの atReady()の中に一行追加
override protected function atReady():void{
//↓これを追加
this.addEventListener(IOErrorEvent.IO_ERROR, function():void { trace("エラー") } );
}

Preloader.asのatReady()の中で、thisに対してIOErrorのハンドリングを書けばOKです。

なぜ、thisに書くかといえば、Preloader.asの親クラス、CastPreloader.asの中にこの一行があるので。

_loader.contentLoaderInfo.addEventListener( IOErrorEvent.IO_ERROR, super.dispatchEvent );
//_loaderはindex.swfを読むためのもの

リスナー関数でsuper.dispatchEventを飛ばしてるから、Preloader.asのthisでイベントを取れるようです。

ちなみに、CastPreloader.as内の_loaderは、Preloader.asからはcontentLoaderInfoで参照が取れるので、Preloader.as内で、

//thisの代わりにcontentLoaderInfoでイベントをハンドリング
contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, function():void { trace("エラー") } );

という感じで書いてみると、一応traceは出力されるんですけども、traceの前に最初のエラーが表示されてしまい、まったく意味がないことになりました。
なので、contentLoaderInfoではなく、素直にthisでIOErrorEventをハンドリングすればOK。