アーカイブ

Flex 3.4 SDK の SystemManager バグ

Flex アプリケーションのプリローダーがローディングしているときにステージをクリックすると、SystemManager がランタイムエラーを発生する問題を発見しました。

この問題は、デフォルトのプリローダーを使用しても発生しますし、プリローダーのローディング時間が長ければ長いほど発生するリスクが増えます。

新規作成直後で最小状態の Flex アプリケーションでも、プリローダーが一瞬表示されるので、この隙にマウスを連打するなどしてステージをクリックすればアウトです。

原因は、SystemManager の 5649 行目です。

5646 : private function stageEventHandler(event:Event):void
5647 : {
5648 :     if (event.target is Stage)
5649 :         mouseCatcher.dispatchEvent(event);
5650 : }

mouseCatcher は、プリローダーのローディングが完了するまで NULL なのですが、stageEventHandler はプリローダー動作中も呼び出されます。つまり、mouseCatcher の NULL チェック漏れです。

この問題は Gumbo にもあったようで、Flex 4 では fix されています。
https://bugs.adobe.com/jira/browse/SDK-22682

当面の回避策
プリローダークラスを自作して、ステージの MouseEvent.MOUSE_DOWN イベントを SystemManager 内のリスナーより早く拾って、イベントの伝播を止める。

面倒だと感じる方は、以下のように DownloadProgressBar クラスを継承することをおすすめします。

package {
import flash.events.Event;
import flash.events.MouseEvent;
import mx.preloaders.DownloadProgressBar;
public class MyPreloader extends DownloadProgressBar {
    public function MyPreloader() {
        super();
        addEventListener(Event.COMPLETE, onCompleteHandler);
        addEventListener(Event.ADDED_TO_STAGE, addedToStateHandler, false, int.MAX_VALUE, true);
    }
    protected function addedToStateHandler(event:Event):void {
        stage.addEventListener(MouseEvent.MOUSE_DOWN, stageMouseDownHandler, false, int.MAX_VALUE, true);
        removeEventListener(event.type, arguments.callee);
    }
    protected function stageMouseDownHandler(event:MouseEvent):void {
        event.stopImmediatePropagation();
    }
    protected function onCompleteHandler(event:Event):void {
        stage.removeEventListener(MouseEvent.MOUSE_DOWN, stageMouseDownHandler, false);
        removeEventListener(event.type, arguments.callee);
    }
}
}