LoginSignup
1
1

More than 5 years have passed since last update.

DataProviderを更新をして一覧に反映されない時の回避方法

Posted at

ListにDataProviderのデータが一部しか表示されなくなってしまう現象に遭遇。
再現コードは以下。

Sample.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
               creationComplete="creationCompleteHandler(event)">

    <fx:Script>
        <![CDATA[
            import com.adobe.serialization.json.JSON;

            import mx.collections.ArrayCollection;
            import mx.events.FlexEvent;

            [Bindable]
            protected var dataProvider:ArrayCollection = new ArrayCollection();

            private var cache:Dictionary = new Dictionary();

            private var selectedPref:String;

            /**
             * 初期化完了イベント
             * @param event
             */
            protected function creationCompleteHandler( event:FlexEvent ):void {
                request( "tokyo" );
            }

            /**
             * データ取得要求
             * @param pref 取得対象の都道府県名
             */
            protected function request( pref:String ):void {
                selectedPref = pref;
                if ( cache[selectedPref] == null ) {
                    var url:String = "http://animemap.net/api/table/" + selectedPref + ".json?timestamp=" + new Date().getTime();
                    var loader:URLLoader = new URLLoader();
                    loader.addEventListener( Event.COMPLETE, loadCompleteHandler );
                    loader.load( new URLRequest( url ) );
                } else {
                    refresh();
                }
            }

            /**
             * データロード完了イベント
             * @param e
             */
            protected function loadCompleteHandler( e:Event ):void {
                var loader:URLLoader = e.target as URLLoader;
                var data:Object = JSON.decode( loader.data as String );

                var list:Array = data["response"]["item"];
                var dp:ArrayCollection = new ArrayCollection();
                for each ( var obj:Object in list ) {
                    dp.addItem( obj.title );
                }

                cache[selectedPref] = dp;
                refresh();
            }

            /**
             * 描画の更新
             */
            protected function refresh():void {
                dataProvider = cache[selectedPref];
                dataProvider.refresh();
            }

            /**
             * 一覧のクリア
             */
            protected function clear():void {
                dataProvider = new ArrayCollection();
                dataProvider.refresh();
                cache = new Dictionary();
            }

            /**
             * 取得ボタンクリックイベント
             * @param event
             */
            protected function btnReload_clickHandler( event:MouseEvent ):void {
                request( ddlPref.selectedItem.label );
            }

            /**
             * クリアボタンクリックイベント
             * @param event
             */
            protected function btnClear_clickHandler( event:MouseEvent ):void {
                clear();
            }

            /**
             * クリアして取得ボタンクリックイベント
             * @param event
             */
            protected function btnNoCache_clickHandler( event:MouseEvent ):void {
                clear();
                request( ddlPref.selectedItem.label );
            }
        ]]>
    </fx:Script>

    <fx:Declarations>
        <!-- 非ビジュアルエレメント (サービス、値オブジェクトなど) をここに配置 -->
    </fx:Declarations>

    <s:List id="lstTv" width="400" height="300" dataProvider="{dataProvider}">
        <s:layout>
            <s:TileLayout/>
        </s:layout>
    </s:List>
    <s:HGroup x="10" y="500">
        <s:DropDownList id="ddlPref" selectedIndex="0">
            <s:ArrayCollection>
                <s:source>
                    <fx:Object label="tokyo"/>
                    <fx:Object label="kanagawa"/>
                    <fx:Object label="chiba"/>
                    <fx:Object label="saitama"/>
                </s:source>
            </s:ArrayCollection>
        </s:DropDownList>
        <s:Button id="btnReload" label="取得" click="btnReload_clickHandler(event)"/>
        <s:Button id="btnClear" label="クリア" click="btnClear_clickHandler(event)"/>
        <s:Button id="btnNoCache" label="クリアして取得" click="btnNoCache_clickHandler(event)"/>
    </s:HGroup>
</s:Application>

dataProvider.refresh();の前に
一覧を強制的に描画更新するlstTv.validateNow();を呼ぶことで回避ができる。
がvalidateNowはとても重い処理だということでフラグつけてキャッシュクリアした時のみ行うなどとしたほうが良さげ。

protected function refresh():void {
    lstTv.validateNow();
    dataProvider = cache[selectedPref];
    dataProvider.refresh();
}
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1