태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.
밤하늘의 실제별, 나도 가질 수 있다?!

[Flex] Collection 계열의 클래스와 List 계열 컴포넌트의 데이터 처리

2008/09/26 18:50

 

[공지]이미지나 링크가 깨졌다면 댓글 부탁드립니다.

Flex에서 ArrayCollection, XMLListCollection은 List 계열 비주얼 컴포넌트(Visual Component)인 Tree, DataGrid등에 구현된 dataProvider() 메소드를 통해 값이 셋팅한다. 굳이 이런 Collection 계열을 dataProvider() 메소드로 받는 이유가 있다. 이 글 목표는 그 이유를 아는 것이다.

먼저 Collection 계열 클래스인 ArrayCollection과 XMLListCollection에 대해서 알아본 다음, List 계열 컴포넌트와의 관계를 살펴보면서 앞서 지적한 이유를 알아보자.


1. Collection 계열 클래스의 구조(ArrayCollection, XMLListCollection 분석)

먼저 Collection 계열 클래스의 구조를 보자. 아래 그림과 같이 ArrayCollectionXMLListCollectionListCollectionView를 확장해서 만들었다. 그리고 ListCollectionViewIEventDispatcher를 확장한 ICollectionIList, 그리고 IMXMLObject 등의 인터페이스를 구현했다.
 
사용자 삽입 이미지

Collection 계열 클래스의 구조


ICollection은 데이터의 정렬 및 필터링을 담당하고 IList는 데이터 추가,삭제,수정 기능 담당한다. 이 부분에 대한 설명은 검쉰님의 "ArrayCollection에 대한 이해" 를 보시면 충분히 공부할 수 있을 것이다.

여기서 주로 다루고 싶은 내용은 Collection계열의 클래스가 IEventDispatcher를 구현했다는 것이다. 이것이 뜻하는 것은 Collection계열의 데이터가 변경되면 이벤트를 송출해준다는 것을 의미한다. 데이터 변경시 CollectionEvent를 COLLECTION_CHANGE라는 type으로 이벤트를 송출한다.

public function set list(value:IList):void

{

    if (_list != value)

    {

        var oldHasItems:Boolean;

        var newHasItems:Boolean;

        if (_list)

        {

            _list.removeEventListener(CollectionEvent.COLLECTION_CHANGE,

                                      listChangeHandler);

            oldHasItems = _list.length > 0;

        }

 

        _list = value;

 

        if (_list)

        {

            // weak listeners to collections and dataproviders

            _list.addEventListener(CollectionEvent.COLLECTION_CHANGE,

                                  listChangeHandler, false, 0, true);

            newHasItems = _list.length > 0;

        }

 

        if (oldHasItems || newHasItems)

            reset();

        dispatchEvent(new Event("listChanged"));

    }

}



위 메소드는 ListCollectionView의 setter메소드인 list의 구현부다. IList 인터페이스를 구현한 데이터가 들어오면 _list에 값을 참고하고 그 데이터가 변경될때 listChangeHandler 메소드를 호출한다.

ArrayCollection이나 XMLListCollection을 사용하신 분은 알겠지만 둘다 source getter/setter 메소드가 정의되어 있다.  ArrayCollection은 source로 Array를 받고 XMLListCollection은 XMLList를 받는다.

아래는 ArrayCollection의 source setter이다.

public function set source(s:Array):void

{

    list = new ArrayList(s);

}

다음 아래는 XMLListCollection의 source setter이다.

public function set source(s:XMLList):void

{

    if (list)

        XMLListAdapter(list).source = null;

   

    list = new XMLListAdapter(s);

}

ArrayCollection과 XMLListCollection은 둘다 ListCollectionView 내부에 구현한 list setter 메소드에 IList를 구현한 ArrayList와 XMLListAdapter를 생성하여 대입하고 있다.

사용자 삽입 이미지

ArrayList와 XMLListAdapter 구조



위 그림처럼 ArrayList와 XMLListAdapter는 IList를 구현했기 때문에 내부적으로 addItem(), addItemAt()등이 구현되어 있고 IList는 IEventDispather를 확장함에 따라 addItem(), removeItem()등과 같은 메소드를 통해 데이터가 변경되면CollectionEvent를 송출하게 된다.

대입절차를 살펴보자면 Array값이 ArrayCollection의 source()에서 ArrayList값으로 변경되어 ListCollectionView의 setter list()를 통해_list:IList값으로 등록된다. 거의 같은 방법으로 XMLList는 XMLListCollection의 source()에서 XMLListAdapter값으로 변경되어 ListCollectionview의 setter list()를 통해 _list:IList값으로 등록된다.

이해를 돕기 위해 ArrayList의 구조를 조금 보자. IList를 구현한 ArrayList는 아래와 같이 addItemAt() 메소드를 구현했다.

public function addItemAt(item:Object, index:int):void

{

    if (index < 0 || index > length)

        {

               var message:String = resourceManager.getString(

                       "collections", "outOfBounds", [ index ]);

        throw new RangeError(message);

        }

       

    source.splice(index, 0, item);

 

    startTrackUpdates(item);

    internalDispatchEvent(CollectionEventKind.ADD, item, index);

}


위 함수는 데이터를 원하는 위치에 추가할때 사용하는 ArrayList의 메소드이다. 데이터를 추가하게 되면 아래에 있는 internalDispatchEvent()를 호출한다.

private function internalDispatchEvent(kind:String, item:Object = null, location:int = -1):void

{

        if (_dispatchEvents == 0)

        {

               if (hasEventListener(CollectionEvent.COLLECTION_CHANGE))

               {

                var event:CollectionEvent =

                new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);

                event.kind = kind;

                event.items.push(item);

                event.location = location;

                dispatchEvent(event);

            }

        …(생략)

}

}

이로써 IList를 구현한 ArrayList나 XMLListAdapter는 데이터가 추가, 수정, 삭제, 변경등이 일어날때 CollectionEvent를 송출하는 것을 확인할 수 있다.

결국 ListCollectionView의 list setter 메소드로부터 IList를 구현한 ArrayList와 XMLListAdapter의 값이 _list에 대입되고 _list.addEventHandler()를 구현함으로써 _list의 데이터가 변경되면 자동적으로 CollectionEvent가 송출된다.

정말 그런지 살펴보자. IList를 구현한 ListCollectionView내부에는 setItem(), addItem(), addItemAt() 등의 메소드가 정의되어 있다. 이들 함수로부터 _list:IList의 _list.setItem(), _list.addItem(), _list.addItemAt()이 호출된다. 그러므로 ArrayList나 XMLListAdapter의 setItem(), addItem(), addItemAt()을 호출하는 것과 동일하다. 결국 ListCollectionView의 setter인 list 메소드안에 _list.addEventHandler()로 등록한 핸들러 메소드 listChangeHandler()를 호출하게 된다. 다음 코드는 listChangedHandler() 핸들러 메소드이다.

private function listChangeHandler(event:CollectionEvent):void

{

    if (autoUpdateCounter > 0)

    {

        if (!pendingUpdates)

        {

            pendingUpdates = [];

        }

        pendingUpdates.push(event);

    }

    else

    {

        switch (event.kind)

        {

            case CollectionEventKind.ADD:

                addItemsToView(event.items, event.location);

            break;

 

            case CollectionEventKind.RESET:

                reset();

            break;

 

            case CollectionEventKind.REMOVE:

                removeItemsFromView(event.items, event.location);

            break;

 

            case CollectionEventKind.REPLACE:

                 replaceItemsInView(event.items, event.location);

            break;

 

            case CollectionEventKind.UPDATE:

                 handlePropertyChangeEvents(event.items);

            break;

 

            default:

                dispatchEvent(event);

        } // switch

    }

}


위 이벤트 핸들러는 ArrayList또는 XMLListAdapter의 데이터가 변경될 때 발생하는 CollectionEvent를 처리하는 메소드이다. 어떤 종류의 데이터 처리를 했느냐에 따라 다음 처리를 위해 switch문에서 이벤트 kind값을 참고하여 관련 메소드를 호출한다. 예를 들어 데이터를 추가한 경우를 살펴보자. 그럼 CollectionEventKind.ADD 부분에서 다음과 같은 addItemsToView() 메소드가 호출된다.

private function addItemsToView(items:Array, sourceLocation:int,

                                  dispatch:Boolean = true):int

{

        …(생략)

    if (dispatch && addedItems.length > 0)

    {

        var event:CollectionEvent =

            new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);

        event.kind = CollectionEventKind.ADD;

        event.location = addLocation;

        event.items = addedItems;

        dispatchEvent(event);

    }

        …(생략)

}

위와 같이 데이터가 추가되면 CollectionEventKind.ADD를 이벤트 kind로 하여 CollectionEvent가 송출되는 것을 확인할 수 있다. 또한 event.location, event.items에 의해 데이터가 변동된 위치와 어떤 데이터가 변동되었는지도 알 수 있다.

결국 ArrayCollection, XMLListCollection의 addItem(), addItemAt(), setItemAt()등을 호출하면 변경된 데이터에 대한 이벤트가 송출되고 데이터 변경에 따른 다른 로직 구현을 마련할 수 있게된다.


이것만은 꼭 알아두자!
Array와 XMLList은 데이터일 뿐이다. 데이터 변동이 있더라도 외부에 알릴 수 있는 통로가 없다. 그의 단점을 보완한것이 ArrayList와 XMLListAdapter이다. 이는 IList를 구현했으며 원하는 위치에 데이터를 바꿀 수 있고 그에 따라 이벤트를 송출할 수 있다. ArrayCollection과 XMLListCollection은 IList, ICollection등을 구현해서 IList기능 뿐이 아니라 ICollection의 데이터 정렬/필터링 기능을 가진다.



2. List 계열 컴포넌트의 구조

Flex의 List 계열의 컴포넌트들은 데이터를 리스트화하여 화면에 보여주기 위한 비주얼 컴포넌트(visual component)이다. Collection 계열의 클래스들이 데이터를 처리하기 위한 것이라면 List 계열 컴포넌트의 가장 큰 목적은 Collection 계열의 클래스의 데이터를 가시화하는 것이다. 가시화를 위해 List계열 컴포넌트는 UIComponent를 기반으로 만들어 졌으며 이들의 핵심 클래스는 ListBase로써 이를 확장하여 목적에 맞게 제작되었다. 자주 사용하는 List, DataGrid가 모두 ListBase를 확장해서 만들어진 것이다. 아래 그림에서 그 관계를 알 수 있다.

사용자 삽입 이미지

List 계열 컴포넌트의 구조



그러므로 List 계열 컴포넌트는 ListBase를 이해하는 것이 순서이다.

여기서 언급할 것은 앞서 설명한 Collection계열의 클래스와 ListBase의 관계이다.

Collection 계열인 ArrayCollection의 인스턴스값이 ListBase의 dataProvider() 메소드에 인자로 넘어가게 되면 그때부터는 ArrayCollection의 데이터가 변경에 대응하여 ListBase에 변경된 데이터를 가시화한다. 여기서 중요하게 생각할 것은 ListBase의 데이터를 수정하는 것이 아니라 ArrayCollection의 데이터가 수정된다는 점과 ArrayCollection 데이터가 수정되면 자동으로 ListBase에 알려준다는 것이다. ListBase의 dataProvider() 메소드는 이런 관계를 만들어주는 역할을 하는 것이다.


그럼, 상세한 이해를 위해 ListBase를 분석해보겠다.
위 그림에서 ListBase는 ICollectionView 형태의 collection이라는 이름의 변수를 사용하고 있다. 아래 코드를 보면 확인할 수 있겠다.

public class ListBase extends ScrollControlBase

                      implements IDataRenderer, IFocusManagerComponent,

                      IListItemRenderer, IDropInListItemRenderer,

                      IEffectTargetHost

{

        …(생략)

 

        protected var collection:ICollectionView;

 

 

        …(생략)

 

}


ListBase의 collection 변수가 protected인 것에 주목하자. ListBase를 확장하는 모든 클래스(List, DataGrid등)은 이 변수를 사용할 수 있음을 알 수 있다.

ListBase의 dataProvider()에서 이 collection 변수를 설정한다. 아래 코드를 보자.

public function set dataProvider(value:Object):void

    {

        if (collection)

        {

            collection.removeEventListener(CollectionEvent.COLLECTION_CHANGE, collectionChangeHandler);

        }

 

        if (value is Array)

        {

            collection = new ArrayCollection(value as Array);

        }

        else if (value is ICollectionView)

        {

            collection = ICollectionView(value);

        }

        else if (value is IList)

        {

            collection = new ListCollectionView(IList(value));

        }

        else if (value is XMLList)

        {

            collection = new XMLListCollection(value as XMLList);

        }

        else if (value is XML)

        {

            var xl:XMLList = new XMLList();

            xl += value;

            collection = new XMLListCollection(xl);

        }

        else

        {

            // convert it to an array containing this one item

            var tmp:Array = [];

            if (value != null)

                tmp.push(value);

            collection = new ArrayCollection(tmp);

        }

 

        …(생략)

 

collection.addEventListener(CollectionEvent.COLLECTION_CHANGE, collectionChangeHandler, false, 0, true);

 

…(생략)

 

}



value는 Object가 들어오지만 어떤 형태의 값을 가지냐에 따라서 그에 맞게 대응하여 ICollectionView 계열 클래스 형태로 바뀌는 것을 볼 수 있다. 어떤 값이 들어오든지 ICollectionList 형태로 데이터가 만들어지도록 구현된 것에 주목하길 바란다. value가 ArrayCollection 형태로 들어온다면  "else if (value is ICollectionView)" 조건에 의해  collection = ICollectionView(value) 로 대입된다.

만약 value가 ArrayList나 XMLListAdapter라면 이 클래스는 IList를 구현했기 때문에 "else if (value is IList)" 조건에서 collection = new ListCollectionView(IList(value)); 로 대입되는 것을 볼 수 있다. 참고로 ArrayList와 XMLListAdapter는 데이터가 변경되면 CollectionEvent를 송출한다고 했다. 하지만 이들 클래스는 ICollectionList를 구현하지 않아 정렬/필터링 기능이 없다. 이 기능이 필요 없을때만 사용하자.


언급하고 싶은 중요한 부분은 그 다음이다.
dataProvider()의 아래부분에 collection.addEventListener(CollectionEvent.COLLECTION_CHANGE, collectionChangeHandler) 부분이 있다. 즉, ICollection 형태의 데이터가 변경되면 collectionChangedHandler 메소드에서 변경된 데이터를 반영하여 가시화 시키겠다는 것을 유추할 수 있다.

그럼 데이터가 변경될 때 호출되는 collectionChangedHandler() 메소드가 어떻게 구현되었나 보도록 하자.

protected function collectionChangeHandler(event:Event):void

{

    var len:int;

    var index:int;

    var i:int;

    var data:ListBaseSelectionData;

    var p:String;

    var selectedUID:String;

 

    if (event is CollectionEvent)

    {

        var ce:CollectionEvent = CollectionEvent(event);

 

if (ce.kind == CollectionEventKind.ADD)

        {

            prepareDataEffect(ce);                       

// special case when we have less than a screen full of stuff

            if (ce.location == 0 && verticalScrollPosition == 0)

            {

                try

                {

iterator.seek(CursorBookmark.FIRST);

                    if (!iteratorValid)

                    {

                        iteratorValid = true;

                        lastSeekPending = null;

                    }

                }

                catch(e:ItemPendingError)

                {

                    // trace("IPE in ADD event");

                    lastSeekPending = new ListBaseSeekPending(CursorBookmark.FIRST, 0)

                    e.addResponder(new ItemResponder(seekPendingResultHandler, seekPendingFailureHandler,

                                                        lastSeekPending));

                    iteratorValid = false;

                    // do nothing, we'll repaint when the data arrives

                }

            }

            else if (listType == "vertical" && verticalScrollPosition >= ce.location)

            {

                super.verticalScrollPosition = super.verticalScrollPosition + ce.items.length;

            }

            var emitEvent:Boolean = adjustAfterAdd(ce.items, ce.location);

            if (emitEvent)

                dispatchEvent(new FlexEvent(FlexEvent.VALUE_COMMIT));

        }

        else if (ce.kind == CollectionEventKind.REPLACE)

        {

               …(생략)

        }

        else if (ce.kind == CollectionEventKind.REMOVE)

        {

               …(생략)

        }

        else if (ce.kind == CollectionEventKind.MOVE)

        {

               …(생략)

}

        else if (ce.kind == CollectionEventKind.REFRESH)

        {

               …(생략)

        }

        else if (ce.kind == CollectionEventKind.RESET)

        {

               …(생략)

        }

        else if (ce.kind == CollectionEventKind.UPDATE)

        {

               …(생략)

}

    }

 

    itemsSizeChanged = true;

 

    invalidateDisplayList();

}

 

예상대로 변수 collection:ICollectionView에 어떻게 데이터가 변경되었냐에 따라서 다른 동작을 하도록 만들어져 있다.  한가지 중요한 것은 마지막에 invalidataDisplayList() 메소드를 호출함으로써 데이터를 가시화한다는 것이다.


정리해보자.

List계열의 컴포넌트가 데이터로 ArrayCollection, XMLListCollection와 같이 IList나 ICollectionView를 구현한 클래스의 인스턴스 값을 dataProvider() 메소드에 값으로 넘겨줘야 하는 이유는 명백하다. 즉, 데이터의 변경(IList), 정렬/필터링(ICollection)에 대해서 대처하기 위한 것이다.

만약 Array등과 같이 이벤트를 송출하지 못하는 값을 넣어주면 Array.push()등과 같은 메소드로 값이 변경되더라도 List 계열 컴포넌트에는 데이터 변경에 대한 시각화를 진행하지 못한다.

ArrayList, XMLListAdapter와 같은 값을 넘겨줘도 되지만 만약 정렬/필터링 기능이 필요하지 않을때 쓰면 되겠다.



3. 실습


아래 코드는 간단하게 ArrayCollection의 데이터 변경에 따른 Log출력과 List계열 컴포넌트인 DataGrid를 활용하는 예제이다. 단순히 코드를 보고 이해하는 것보다 디버깅을 하면서 내부적으로 어떻게 동작하는지 살펴보는 것도 좋다고 생각한다.


<?xml version="1.0" encoding="utf-8"?>

<Application xmlns="http://www.adobe.com/2006/mxml" layout="vertical" width="500">

       

        <Script>

               <![CDATA[

                       import mx.events.CollectionEvent;

                       import mx.events.CollectionEventKind;

                      

                       public function collectionEventHandler( event:CollectionEvent):void

                       {

                              switch( event.kind )

                              {

                                      case CollectionEventKind.ADD:

                                             addLog( "Item " + event.location + " added");

                                             break;

                                      case CollectionEventKind.REMOVE:

                                             addLog( "Item " + event.location + " removed");

                                             break;

                                      case CollectionEventKind.REPLACE:

                                             addLog( "Item " + event.location + " replaced");

                                             break;

                                      case CollectionEventKind.UPDATE:

                                             addLog( "Item updated");

                                             break;

                              }

                       }

                      

                       public function addLog( log:String ):void

                       {

                              txtLog.text = log + "\n" + txtLog.text;

                       }

                      

                       public function addPerson():void

                       {

                              ac.addItem( {name:txtName.text, email:txtEmail.text } );    

                              clearInputs();

                       }

                      

                       public function removePerson():void

                       {

                              if( dg.selectedIndex >= 0)

                              {

                                      ac.removeItemAt( dg.selectedIndex );

                              }

                       }

                      

                       public function updatePerson():void

                       {

                              if( dg.selectedItem != null )

                              {

                                      ac.setItemAt( {name:txtName.text, email:txtEmail.text }, dg.selectedIndex );

                              }

                       }

                      

                       public function clearInputs():void

                       {

                              txtName.text = "";

                              txtEmail.text = "";

                       }

               ]]>

        </Script>

 

        <ArrayCollection id="ac" collectionChange="collectionEventHandler(event)">

               <source>

                       <Array>

                              <Object name="지돌스타" email="jidolstar@mail.com"/>

                              <Object name="조이킴" email="joykim@mail.com"/>

                       </Array>

               </source>

        </ArrayCollection>

       

        <Panel title="ArrayCollection 테스트" width="100%">

               <DataGrid width="100%" id="dg" dataProvider="{ac}">

                       <columns>

                              <DataGridColumn dataField="name" headerText="이름"/>

                              <DataGridColumn dataField="email" headerText="전자우편"/>

                       </columns>

               </DataGrid>

               <Form width="100%">

                       <FormItem label="이름" width="100%">

                              <TextInput id="txtName" width="100%" text="{dg.selectedItem.name}"/>

                       </FormItem>

                       <FormItem label="전자우편" width="100%">

                              <TextInput id="txtEmail" width="100%" text="{dg.selectedItem.email}"/>

                       </FormItem>

               </Form>

               <ControlBar horizontalAlign="center">

                       <Button label="추가" click="addPerson()"/>

                       <Button label="변경" click="updatePerson()"/>

                       <Button label="삭제" click="removePerson()"/>

                       <Button label="초기화" click="clearInputs()"/>

               </ControlBar>

        </Panel>

        <Panel title="로그" width="100%" height="150">

               <TextArea id="txtLog" width="100%" height="100%"/>

        </Panel>

       

        <Style>

               Application

               {

                       fontSize:11pt;

               }

        </Style>

</Application>

 


실행화면







4. 생각해보기

1. [Bindable] Metadata 태그가 데이터 변동에도 동작한다고 생각하지 말자.
[Bindable] public var ac:ArrayCollection 처럼 사용할 때 [Bindable]를 사용했기 때문에 ArrayCollection 안에 데이터가 변동되면 당연히 List 계열 컴포넌트에도 변경되어야 하는거 아닌가 착각할 수 있다.

[Bindable] Metadata 태그의 역할은 ArrayCollection의 인스턴스 값 자체가 바뀔 때 데이터 바인딩을 위한 것임을 기억하자. 만약 <DataGrid dataProvider="{ac}"/>라고 사용했다면 [Bindable]의 역할은 ArrayCollection 내의 데이터 변동에 따라 List계열 컴포넌트에 적용되는 것이 아니라 ArrayCollection 자체 인스턴스가 변동될때 List 계열 컴포넌트의 함수 dataProvider()를 호출하는 것이다.

정리해보면 [Bindable] Metadata Tag는 ArrayCollection 인스턴스 자체가 변동될때 dataProvider에 변경된 ArrayCollection 인스턴스를 전달하여 데이터 바인딩 처리하는 것이고 ArrayCollection 내부에 데이터가 변동될때는 CollectionEvent가 송출되어 List 컴포넌트 내에서 처리하는 것이다. 그 차이를 분명히 알아두자!

2. ArrayCollection의 source를 참고하여 data를 추가하지 말자.
ArrayCollection에 데이터를 추가하기 위해 addItem()을 사용하지 않고 ArrayCollection.source.push()와 같이 사용하면 ArrayCollection의 데이터가 변경되지만 변경에 따른 이벤트는 송출하지 않기 때문에 ArrayCollection을 사용하는 List 계열의 컴포넌트는 변경된 내용을 알 수 없어 시각화 처리를 할 수 없다. 이처럼 엉뚱하게 ArrayCollection.source.push() 식으로 데이터를 가공하고 List 계열 컴포넌트가 시각화되길 기대하는 일은 없도록 해야겠다.

3. Flex SDK와 LiveDoc을 적극 활용해서 이해하자.
Flex SDK를 올바르게 사용하기 위해서 어떤 구조로 되어 있는가 공부해볼 필요가 있다. Flex 서적에 나오지 않은 내용은 직접 Flex SDK를 보고 LiveDoc을 통해 전체적인 사용법을 익히는게 중요하다.
Flex 중급으로 올라갈수록 각종 컴포넌트 만드는 일이 많아지고 Flex SDK의 컴포넌트를 확장하여 제작하는 일이 빈번해진다. 이럴때는 서적에 나와 있는 내용만 가지고는 한계를 느낄 것이라 생각한다. 이에 대처하기 위해 Flex SDK 분석, LiveDoc 활용, 관련 문서 검색이 필수이다. Flex는 그렇게 공부해야 한다!!!



5. 참고자료

검쉰님의 "ArrayCollection에 대한 이해" : http://warkyman.tistory.com/171
ArrayCollection : http://livedocs.adobe.com/flex/3/langref/mx/collections/ArrayCollection.html
XMLListCollection : http://livedocs.adobe.com/flex/3/langref/mx/collections/XMLListCollection.html
ListCollectionView : http://livedocs.adobe.com/flex/3/langref/mx/collections/ListCollectionView.html
CollectionEvent : http://livedocs.adobe.com/flex/3/langref/mx/events/CollectionEvent.html
CollectionEventKind : http://livedocs.adobe.com/flex/3/langref/mx/events/CollectionEventKind.html


글쓴이 : 지돌스타(http://blog.jidolstar.com/375)
크리에이티브 커먼즈 라이선스
Creative Commons License

Adobe Flash Platform , , , , , , , , , , , ,

Trackback 주소: http://blog.jidolstar.com/trackback/375
  1. 2009/09/16 10:55
    Flex 애플리케이션의 성능을 보장하는 10가지 팁 Tracked from 열이아빠의 RIA 이야기
  1. Blog Icon
    눈송이

    너무 유익한 글이었습니다 감사합니다~^^
    저도 얼마전에 이러한 역할을 느껴서 Collection 타입을 필요할때만 사용하고 있었는데
    이렇게 글을 보고 자세하게 알게되었습니다^^
    빨랑 저도 연구하는 습관을 들여야겠네요~^^

  2. 예 프로젝트 하다보면 데이터와 View와의 분리가 필요할때가 정말 많더군요. 이때 이런 Collection 계열 클래스의 동작방식에 대해서 이해를 못하고 있다면 삽질을 여러번 하게 되더군요. (제 경험이 그랬습니다. ^^)

    혼자아는 것보다 함께 알아가면 더 좋잖아요? ㅎ
    블로그을 이용하면 함께 할 수 있는 일이 참 많은 것 같아요. 눈송이님도 동참해주시면 정말 좋겠습니다. ^^

  3. 좋은 글이군요 ;)

  4. Blog Icon
    상지니

    글 아주 잘 보았습니다.
    근데 궁금한게 하나 있습니다.
    "ArrayCollection 인스턴스 자체가 변동될때" 와 "ArrayCollection 내부에 데이터가 변동될때" 의 차이점이
    뭔가여?
    둘다 인스턴스, 그러니깐 실체개념이 아닌가여?
    글 잘 읽다가 갑자기 혼돈이 오네여.ㅠ.ㅠ
    두 문장의 차이점을 알고 싶습니다.
    도저히 이해가 안가네여.

  5. ArrayCollection 인스턴스 자체가 변동될때라는 것은
    var a:ArrayCollection = new ArrayCollection()
    이였는데...
    나중에
    a = new ArrayCollection()
    이라고 보면 됩니다.
    더욱 정확하게 말씀드린다면 ArrayCollection 객체를 참조하고 있는 변수가 다른 ArrayCollection 객체를 참조하는 경우를 말합니다. 이 경우에는 데이터바인딩과 연관되어 dataprovider에 변동된 ArrayCollection값이 적용됨니다.


    그리고 ArrayCollection내부의 데이터가 변경된다는 것은 내부적으로 ArrayCollection은 ArrayList를 감싸고 있습니다. ArrayList의 값이 추가,삭제,업데이트등이 일어하는 경우에는 이벤트가 발생합니다. 외형적으로는 ArrayCollection안에 있는 데이터가 변동되는 경우 이벤트가 발생한다는 의미입니다. 이렇게 ArrayCollection은 그대로 있지만 그 내부 데이터가 변동되는 경우에는 데이터 바인딩 처리를 할 수 없습니다. ArrayCollection객체에 대한 참조는 변동되지 않았기 때문이지요. 그래서 데이터 변동시에는 발생되는 이벤트를 청취하여 List객체에서 반영하도록 해야합니다.

    이해가시는지요? ^^