2012年1月25日水曜日

FlexでSharedObjectに大きなデータを保存する時の注意点

FlexでSharedObjectにデータを保存する時に、ある程度のデータサイズまでは特に問題はない。

しかし、大きなデータを保存する時には、こんな感じでユーザーに許可を求めるダイアログが自動的に表示される。

これが厄介。

例えばこんなコード。

function saveByteArray(ba:ByteArray):void {
    var so:SharedObject = SharedObject.getLocal("config", "/");
    so.data.bytearray = ba; //ByteArrayが50MB程度と仮定
    so.flush(); //この段階でユーザーにローカルストレージに保存する許可を求めるダイアログが表示される
}

flush()した時点でユーザーにローカルストレージに保存する許可を求めるダイアログが表示される。

ここでユーザーが「拒否」した場合は仕方ない。しかしユーザーが「許可」した場合は保存できるものと期待した。しかし、その期待はハズれた。保存されない!

ただ、絶対か?と言われるとそうでもない。調べた限りでは、FP11系ではたまに保存できるし、FP10系ではごくごくたまに保存できる。しかし、この不安定さは保存できないと言っていいと思う。

つまり、大きなデータを保存する時に、まだユーザーの許可を得ていない状態で保存をすると保存できないということだ。

逆に言うと、予め許可を得ていれば保存できるということでもある。実際、2回目にはちゃんと保存できるのだ。

そこで、まずはflush()メソッドの引数を使ってわざと大きなデータを保存する「フリ」をする。許可をもらったら実際に保存する。という処理をすることにした。

書いてみると、意外と('A`)マンドクセな処理だった。

function saveByteArray(ba:ByteArray):void {

    Alert.show("ローカルストレージへの保存許可をチェックします", "ローカルストレージ保存許可チェック", Alert.OK, null, savePermissionCheck);
    function savePermissionCheck():void {

        //SharedObject取得
        var so:SharedObject = SharedObject.getLocal("config", "/");

        //ローカルストレージ保存許可ダイアログの結果処理
        so.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
        function onNetStatus(evt:NetStatusEvent):void {
            so.removeEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
            if (evt.info.code == "SharedObject.Flush.Success") {
                trace("許可された");
                save();
            } else {
                trace("許可されなかった");
            }
        } //END onNetStatus()

        //まずは50MB程度を保存する「フリ」をする
        var status:String = so.flush(1024*1000*50);

        //許可済みだった場合
        if (status == SharedObjectFlushStatus.FLUSHED) {
            so.removeEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
            trace("許可済みだった");
            save();
        } else {
            trace("許可されてなかった"); //この場合にローカルストレージ保存許可ダイアログが表示される
        }

        //保存処理
        function save():void {

            //ここでバイト列を保存
            so.data.bytearray = ba;
            status = cfg.flush();

            //成功した場合(するはず)
            if (status == SharedObjectFlushStatus.FLUSHED) {
                trace("保存成功");
            } else {
                trace("保存失敗");
            }

        } //END save()

    } //END savePermissionCheck()

} //END saveByteArray()

しかし、これでFP10系でもFP11系でも保存できるようになった。