すげぇ、はまったのでメモしておきます。
まずは状況説明
- テスト環境(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も同様の現象が起きますよ、ということ。
なんともいやらしい罠でした。
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。
Tags: AS3, Flash, progression4