본문 바로가기

Blog/Flex

Flex 4 Component (1) - Lifecycle

Component Lifecycle

하던 일을 잠시 내려놓고 Flex4에 대해서 정리해보려 합니다. ActionScript 2.0에서 3.0을 거쳐 Flex3까지 계속해서 사용해 왔던터라 Flex4를 접하는게 생소한 일은 아니지만, 역시 어물쩡 그냥 사용할 수는 없고 이쯤에서 다시한번 개념정리가 필요한 것 같아 포스팅 합니다.

Flex는 component 주기만 잘 알고 있어도 거의 대부분을 이해하고 있다고 할 수 있습니다. 다르게 표현하자면 컴포넌트 주기에 대해 이해하지 못하면 Flex를 효율적으로 사용할 수 없다는 것이겠죠.. 각설하고 Component Lifecycle에 대해 한번 보겠습니다. Flex컴포넌트는 인스턴스가 생성되는 시점에 제거되는 시점까지 일련의 규칙에 의해서 동작하게 됩니다. 이걸 주기(Lifecycle)라고 부르는데 이 주기의 핵심은 무효화(invalidation)과 유효화(validation) 과정을 거치면서 Flash Player의 렌더링을 최적화 시켜주는데 있습니다. 결국 Flex에서 컴포넌트를 제작하는 것은 Flash 에서와는 달리 프레임웍에서 제공하는 무효화/유효화 과정을 중간에 거치도록 강제 함으로써 자연스럽게 퍼포먼스 향상을 유도하는 것입니다.

먼저 SWF 파일의 프레임 관점에서 이 과정을 도식화 해보면 다음과 같습니다.

사용자가 작성한 코드는 프레임 내에서 언제든지 호출되어 화면을 갱신해야 할만한 속성들 (크기, 위치…)이 바뀌어도 그때 그때 화면에 적용시키지 않고 보류하고 있다가 프레임의 마지막에 단 한번 렌더링에 적용시킴으로써 Player 에 부하를 최대한 줄임으로써 전체적인 퍼포먼스 향상을 꾀하는 것이 컴포넌트 주기- 무효화, 유효화 과정- 의 목적입니다.

그럼 이번에는 Component의 클래스 관점에서 Lifecycle을 살펴보겠습니다.

Construction

var b:Button = new Button();

보통 Constructor에 그다지 많은 코드를 작성하지는 않습니다. 부모 클래스인 FlexSprite 클래스에서 name 속성이 채워집니다. 필요하면 이벤트 리스너를 추가할 수도 있습니다.

Addition

this.addChild(b);

addingChild(), $addChild(), childAdded() 메서드를 호출합니다. addingChild() 메서드는 parent 속성을 비롯한 document 속성들이 설정됩니다. $addChild() 메서드(low-level player method)는 컴포넌트를 Display List에 추가시킵니다. childAdded() 메서드는 컴포넌트의 child 컴포넌트가 아직 초기화되지 않았다면 child의 initialize() 메서드를 호출함으로써 자신의 초기화가 완료되기 전에 child의 초기화를 모두 진행합니다.

Initialization

Initialize();

위에서 언급했듯이 이 메서드는 parent의 childAdded() 메서드에서 호출됩니다. 메서드가 호출되면 FlexEvent.PREINITIALIZE 이벤트를 발생시킵니다. 또한 child를 생성하고 추가시키는 createChildren() 메서드를 호출한 후 마지막으로FlexEvent.INTIALIZED 이벤트를 발생시킵니다.

Invalidation/Validation cycle (Life)

위에서 보았듯이 무효화/유효화 주기는 컴포넌트의 property 등이 바뀔 때, 이것을 화면에 나타내기 전까지(한 Frame의 마지막 부분까지) Framework차원에서 이 변화에 대한 적용을 연기시키는 방법입니다. 이런 주기를 사용하는 방법은 간단합니다. 변경된 새로운 값을 임시로 변수에 저장해 놓고 변경 되었음을 알리는dirty flag를 설정합니다. 그런 후 해당 invalidate 메서드를 호출합는 것입니다.

좀더 자세히 살펴보자면 LayoutManager 클래스를 살펴볼 필요가 있습니다. LayoutManager 클래스는Application의 실행시에, LayoutManager 의 단일의 인스턴스가 작성되어 UIComponent.layoutManager property에 포함됩니다. 모든 컴퍼넌트는 이 인스턴스를 사용하여 처리(commit), 측정(measurement), 및 레이아웃(layout)의 3 단계에 걸쳐서 실행됩니다. 가장 깊은 단계의 child로부터(bottom-up) 측정하기 시작하여 계산된 값을 가장 바깥의 parent로부터(top-down) 적용시키게 됩니다. 그래서 LayoutManager 는 어떤 컴포넌트에서 invalidate 메서드가 호출되었는지를 항상 관찰하고 있다가 (사실 invalidate 계열의 메서드가 LayoutManager에게 알려준다) Event.RENDER 이벤트가 발생되면 validate 메서드를 호출합니다. 위 그림과 한번 비교해 보시기 바랍니다. 호출되는 validate 메서드는 다음과 같습니다.

  • invalidateProperties à commitProperties
  • invalidateSize à measure
  • invalidateDisplayList à updateDisplayList

validate메서드(validateProperties(),validateSize(), validateDisplayList())가 있으나 레퍼런스에는 보통 메서드를 override하여 사용하지 말 것을 권하고 있습니다. 대신 commitProperties(),measure(), 또는 updateDisplayList() 메서드를 override하여 사용하는데, 결국은 이 메서드들은 각각 validateProperties(),validateSize(),validateDisplayList() 메서드 실행 도중에 호출되는 메서드들 입니다. 모든 유효화가 진행되었을 때 마지막으로 FlexEvent.UPDATE_COMPLETE 를 발생시킵니다.

Removal (death)

this.removeChild(b);

$remeveChild() 메서드를 통해 Display List로부터 컴포넌트를 제거합니다. $ remeveChild() 역시 low-level player method 입니다.

 Flex4에서는?

여기까지는 Flex 3와 Flex4의 컴포넌트가 같습니다. 따라서 Flex 4의 Spark 컴포넌트 또한 위의 주기를 따릅니다. 그럼 달라진 점은 무엇일까요? Spark 컴포넌트는 Flex 3의 Halo 컴포넌트를 기반으로 설계되었습니다. 여기서는 간략하게 소개하고 자세한 내용은 다음으로 미루겠습니다.

UIComponent를 확장한 SkinnableComponent 를 통해 비쥬얼 요소를 비즈니스 로직과 분리시킵니다. 하지만 SkinnableComponent 역시 UIComponent 를 상속받았으므로 위의 Lifecycle을 따릅니다. 생소한 클래스가 아니라 단지 이전에 컴포넌트를 만들기 위해 UIComponent를 상속한 것처럼 Spark 컴포넌트는 SkinnableComponent 클래스를 상속해서 만든 컴포넌트라고 일단 이해하는게 좋을 것 같습니다. 물론 스킨과 비즈니스 로직을 분리하기 위해 새롭게 추가된(확장된) 몇 가지 메서드가 있습니다.

  • SkinnableComponent의 createChildren() 메서드에서는 새로운 attachSkin()메서드를 호출하고 이 메서드는 다시 validateSkinState() 메서드를 호출합니다.
  • attachSkin() 메서드는 컴포넌트의 자식으로skin을 생성하고 추가합니다. 이렇게 추가된 skin 역시 Lifecycle 을 따릅니다.
  • attachSkin() 메서드는 또한 findSkinParts() 메서드를 호출합니다. (skin은 여러 개의 자식(skinPart)으로 이루어 집니다.)
  • findSkinParts() 메서드는 partAdded() 메서드를 호출하고, 꼭 필수 skinPart를 찾지 못한 경우엔 에러를 발생시킵니다.

skin이니 skin part와 같은 생소한 용어가 나오는데, SkinnableComponent를 제작하는데 필요한 비쥬얼 요소가 Skin입니다. 이 Skin을 만들기 위해 사용된(Skin에 정의된) Skin의 child 요소를 SkinnableComponent에서 참조할 때 SkinPart라고 선언합니다. 이 부분은 SkinnableComponent 와 Skin과의 관계에 대한 이해가 필요하므로 Spark 컴포넌트의 다른 내용과 함께 다음 글로 넘깁니다.

참고

이 글은 weblog.mrinalwadhwa.com의 Flex4 Component Lifecycle 내용을 참고로 작성되었습니다.