Creative Wrong Answer


플렉스에서 팝업에 관해서 가장 많이 나오는 질문중 하나가 팝업을 띄울때 어플리케이션의 데이터를 보내고 싶다거나 팝업이 닫힐때 데이터를 받아서 특정 함수를 실행시키고 싶다거나 하는 것이다.

이전에 쓴글 2010/02/17 - [Flex] - 커스텀이벤트 (Custom Event) 만들기 / 사용하기 를 보면 어느정도 알수 있지만 정확하게 팝업을 위해서 쓴 글이 아니기 때문에 실제 사용에 힘들어 하는 사람들을 보게 된다.

그래서 간단한 예제로 구현을 해보고자 한다.




예제를 보면 보낼 데이터에 rinn.kr 이 들어있고 팝업 띄우기를 클릭하면 팝업이 뜨면서 보낸 데이터가 보여진다.
팝업에 보낼데이터 필드에 들어있는 값이 어플리케이션에도 반영된다.

팝업으로 데이터를 보낼때에는 팝업컴포넌트의 public 변수에 그냥 값을 넘겨주기만 하면 되고. 팝업에서 데이터를 받을때에는 이벤트에 실어서 날려주면 된다.

팝업은 팝업을 띄우는 객체의 child로 취급되기 때문에 팝업에서 발생하는 이벤트를 어플리케이션에서 받을 수 있다. 기본적인 이벤트 전파만 이해 하면 사실 간단한 문제다.

워낙 간단하니 소스에 대한 설명은 생략하고 샘플 파일을 첨부하는 걸로 시마이~


저작자 표시 비영리 동일 조건 변경 허락
신고

Comment +7

플렉스의 레이아웃 컨테이너는 여러가지 종류가 있지만 가장 많이 사용되는 것은 Canvas, Box (VBox, HBox) 일것이다.

기본적으로 Canvas 는 absolute 기반으로 즉 좌표를 기반으로 절대위치를 결정해서 아이템을 배치 하게 되고 Box 계열은 vertical 이나 horozontal 정렬 방식으로 다른 아이템들과의 위치를 판단해서 전체적인 배치를 하게 된다.

어느것이 좋냐는 아빠가 좋냐 엄마가 좋냐 정도의 문제가 될수 있으니 일단 배제 하고..
아래 그림과 같은 레이아웃을 만든다고 가정하고 간단하게 구조를 잡아보자..


클릭해서 보면 상단,하단의 위아래로 나눠진 구조에 아래쪽은 좌,우로 나눠진 형태이다.

일반적인 사이트들의 레이아웃이고 관리자화면을 꾸밀때나 게시판 형식을 만들때 자주 보게 되는 형식일 것이다. (나만 이렇게 만드는건 아니겠지 -ㅅ-;)

상단은 높이가 고정되어있고 하단은 나머지 높이를 차지 하게 된다.
하단에서는 우측은 넓이가 고정되어있고 좌측은 우측을뺀 나머지 넓이를 차지하게 된다.

이런 형태의 레이아웃을 만들기 위해서 일반적으로 생각을 할때 위아래로 배치 되어야 하니까 어플리케이션은 vertical로 레이아웃을 설정하고 상단/하단 구분을 위해서 HBox 를 두개 배치 하고 하단 HBox 내부에 다시 데이터 그리드와 패널을 배치 하는 형태가 될것이다.
만약 데이터 그리드 위쪽에 정보를 보여주거나 설명을 위한 라벨만 하나 들어갈려고 해도 하단 VBox를 추가해서 라벨과 데이터 그리드를 넣어야 한다. 몇개 안되는 구조를 위해서 컨테이너가 꽤나 많이 사용되는 것이다.

이런 방법은 예전에 HTML 페이지에서 테이블로 구조를 만들어본 경험이있는 사람들이 즐겨 쓰는 방법이다. 지금은 HTML도 div를 사용해서 적절하게 겹치지 않도록 레이아웃을 하지만.. 전에는 중첩 테이블을 이용해서 td 안에 테이블 또 td 안에 테이블 이런 형태로 레이아웃을 구성했었다.

그렇게 만들었던 경험이 저런식으로 레이아웃을 만들게 되는 것이다.

중첩 구조로 만들때의 문제점은 Flex3 컨테이너가 모든 이벤트 처리 및 스크롤 등을 전부 가지고 있는 놈이라는 거다. 이벤트는 컨테이너를 따라 계속 버블링 되고 스크롤을 사용하던 사용하지 않던 이미 내부적으로는 맹렬하게 계산해서 처리를 하고 있다.

Flex4 에서는 Group이 추가 되면서 저런 문제가 줄어들겠지만 지금 Flex3를 주력으로 사용하고 있는 입장에서는 아무래도 중첩 구조는 퍼포먼스나 이후의 구조변경을 할때에도 부담이 될 수 밖에 없다.

하지만 브라우저 사이즈에 따라서 유동적으로 변경되는 레이아웃을 좌표계를 기반으로 만들기에는 좀 불편하다.

이 포스트에서 소개 하고자 하는것은 제한 레이아웃 생성자인 constraintRowsconstraintColumns 이다.
absolute 타입의 레이아웃에서 미리 화면을 제한해서 분할 하고 그 제한된 위치를 참고해서 레이아웃을 구성할 수 있게 해준다.
constraintRows는 상하단으로 구분을 할때 사용하고 constraintColumns는 좌우측을 구분할때 사용한다.

<mx:constraintRows>
      <mx:ConstraintRow id="title" height="30"/>
     <mx:ConstraintRow id="content" height="100%"/>
</mx:constraintRows>

이 코드는 absolute 로 정의된 어플리케이션의 공간을 상단을 높이 30 으로 하단은 나머지를 사용하도록 미리 분할한다. 분할된 선은 보이지 않는다 -ㅅ-;

<mx:constraintColumns>
      <mx:ConstraintColumn id="list" width="100%"/>
      <mx:ConstraintColumn id="sideBar" width="200"/>
</mx:constraintColumns>

이 코드는 constraintColumns 를 사용하여 좌측을 200으로 우측은 나머지를 사용하도록 분할한다.


컨테이너를 사용하지 않고도 화면을 미리 분할 해놓고 가상의 선을 기준으로 좌표를 지정할 수 있게 되는 것이다.

상단 전체, 하단 전체, 좌측 전체, 우측 전체, 1,2,3,4 로 나눠진 부분공간 모두를 사용해서 원하는 곳에 아이템들을 배치 할 수 있게 된다.
또한 어플리케이션이 absolute 이므로 고정좌표를 사용해서 특정 위치에 특정 아이템을 배치 하는 것도 물론 가능하다.

분할된 가상공간의 좌표를 지정할때는 id:좌표 형식으로 지정하게 된다.
제한 좌표를 사용할때는 top, left, right, bottom 속성으로 레이아웃의 크기를 설정 해주는것이 사용하기 편하다.

예를 들어 3번 위치에 가득차게 데이터 그리드를 배치하고 오른쪽 공간과 5px 정도 떨어져서 간격을 유지 하게 하고싶다면.

<mx:DataGrid  top="content:5" left="list:5" bottom="content:5" right="list:5">

이렇게 설정한다. 상대좌표를 잡을 constraintRow나 column의 아이디를 쓰고 거기서 얼마나 떨어져야 할지를 입력한다.
위 아래는 Row를 참조하고 좌우는 Column을 참조 해서 좌표를 잡게 된다.
저런 좌표를 디자인 뷰에서 직접 입력하기는 힘들지만 완성된 레이아웃은 디자인 뷰에서도 정상적으로 보이게 되니 처음 레이아웃을 잡을때 큰 틀을 설정해놓고 내부 아이템을 세팅해 내가는 형식으로 구성하면 된다.

이 방식으로 만들게 되면 단순 레이아웃을 위한 컨테이너의 중첩을 사용하지 않아도 되기 때문에 코드를 보기에도 깔끔해지고 중첩으로 인한 부담되는 이벤트 버블링도 방지 할 수 있다.

레이아웃만을 위해서 중첩된 컨테이너를 사용하는 것은 지양하자.


저작자 표시 비영리 동일 조건 변경 허락
신고

Comment +4

  • 아도겐~!!!ㅋㅋ

  • 엥 웬 관리자의 승인입니꽈!?

    게다가 자바스크립트 오류있어요~

  • 가변형 컨테이너는 편리하지만 동시에 독이죠.
    항상 느낌이 과거 html에서 유행하던 표안에 표안에 표의 느낌으로 레이아웃을 잡아가는 분위기입니다.

    세계적으로 뭔가 그리드에 대한 꽁수가 아니라 혁신적인 컨테이너 레이아웃에 대한 개발이 필요한 시기인듯합니다.

이전 포스팅에서 환경 세팅을 위한 파일을 받고나서 벌써 시간이 꽤 흘러버렸다..
2010/02/09 - [Flex/BlazeDS / iBatis] - Flex와 BlazeDS, iBatis를 사용하기 위한 환경 설정하기 - 다운로드

환경 세팅은 됐다고 치고 -ㅅ-;
프로젝트를 만들어보자...

포스팅 타겟은 초보자인데.. 어째 좀 불성실한 느낌이 들지만 기본 톰켓환경 세팅등은 다른곳에 워낙 잘 정리되어있으니 구글님을 참고 해서 세팅 하는걸로 하고 넘어간다.

이클립스에 플렉스 플러그인으로 설치되어있고 톰켓 5.5에 BlazeDS.war 파일도 가지고 있으니 이클립스에 서버를 세팅하고 플렉스 프로젝트를 만드는 과정을 그림과 함께 친절하게 따라가보자.

1. 이클립스를 실행한다.
[그림 생략]...

2. 서버를 만들자.
기본 톰켓 서버를 사용하지 않고 이클립스에 물려서 사용한다. 간단하게 켜고 끌수 있고 상황도 바로 바로 파악할 수 있는데다가 로그도 이클립스에 찍힌다. 처음 이클립스를 사용할때 되게 신기해 했던 기억이...
이클립스를 끄면 서버도 꺼지고 버전별로 관리도 되고 암튼 편하다..


프로젝트에서 new - other 클릭


Server - Server 선택 Next


본인 pc에 깔려있는 버전 선택.. 저기 나온다고 해서 안깔려있는 서버가 돌아가는건 아니니 깔려있는걸로 선택.
회사 프로젝트 때문에 톰켓 5.5를 사용하고 있기 때문에 5.5 선택하고 Finish~


프로젝트 네비게이터에 보면 만들어진 서버가 나오게 된다. 간단한 세팅도 할 수 있지만 그런건 다른데서 보기로 하고 여기서는 일단 만들었으니 서버는 끝~

3. 실제 돌아갈 프로젝트를 만든다.

new Project 를 만들고 나오는 창을 살펴보자


어플리케이션 서버 타입을 "J2EE" 를 선택한다.


만들어놓은 서버와 같은 타입을 선택한다. 여기서는 톰켓 5.5

이전 포스트에서 받은 BlazeDS 파일의 경로를 입력한다. ContextRoot 가 aaa 로 되어있는데 저건 신경쓰지 말고 원래의 프로젝트 이름으로 나오도록 그냥 가만히 놔두자 aaa로 고쳐버리면 낭패.. 스샷용으로 만들고 있는거니 일단 고치지 말고 진행하자.


BugReport 라는 프로젝트를 생성했고 프로젝트의 구조는 위의 그림과 같다.
flex_src 는 플렉스쪽 프로젝트가 들어가야 할 폴더이고 src 는 자바 소스 파일이다. 웹컨텐츠는 빌드를 했을때 파일이 나갈 곳이고 톰켓의 루트 폴더가 된다.

4. 프로젝트를 서버에 추가 하자

 하단 퍼스펙티브에 위에서 서버를 추가 했으므로 서버탭이 보이고 현재 서버의 상태가 보일것이다.
설치된 서버를 오른클릭해서 팝업메뉴를 불러서 Add and Remove Projects 를 선택한다.

만든 프로젝트를 오른쪽으로 옮기면 현재 서버에 프로젝트가 추가된다. 이제 생성된 프로젝트를 서버환경으로 테스트가 가능하게 된것이다.
여러개의 프로젝트를 서버에 띄워놓고 테스트가 가능하다. 경로는 http://localhost:8080/프로젝트이름/ 형식이 된다.


프로젝트를 등록했으니 오른쪽에 있는 스타트 버튼을 클릭하면 톰켓 서버가 시작된다.

5. 시작해보자~

생성한 프로젝트의 메인 파일을 F11을 눌러서 실행하게 되면. 서버에서 돌릴꺼냐 플렉스 프로젝트에서 돌릴꺼냐물어보는게 나오는데 그냥 플렉스 프로젝트로 돌리는걸 선택하면 된다.
Run on Server 를 선택하면 당연히 안된다-ㅅ-;;;


이 경로로 실행이 된다면 성공~!!!!

페이지를 찾지 못한다는 404 에러가 나오면 서버가 켜져 있지 않거나 컴파일 경로가 달라서 일것이다.
혹은 서버를 시작하면서 에러가 났다거나.. 등등..

프로젝트 설정에서 Flex build Path 쪽을 살펴 보면서 뭐가 틀렸는지 확인 해보자~

모두 성공하길... -ㅅ-~

ps. BugReport 라는 프로젝트를 하나 완성 시키면서.. 아이템 랜더러와 아이템 에디터 프로젝트 레이아웃이나 이벤트 등 잡다한 걸 묶어서 한방에 다 정리 해버릴까.. 생각 중이긴 한데.. (액션스크립트 트레이닝 책처럼.)
회사 일 하면서 하는거라 언제 완성 될지는 잘 모르겠다 -ㅅ-;;;

뭐 언젠가는 되겠지.

저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 0

Flex Event 기본 설명

Flex2010.02.05 19:46
나는 디자이너 출신이기 때문에 프로그래밍에 대한 심오한 지식이 없다.
대학에서 윈도우 프로그래밍이나 자바, C 관련 언어에 대한 강의를 들었지만 디자인에 더 관심이 많았기 때문에 별로 주의깊에 듣지 않았었고... 그걸 지금 와서 엄청 후회하는 중이다.

Flash2 때 처음 Flash를 접하게 되었고 3 버전부터 사용을 하다가.. 4,5 를 넘어오면서 actionscript가 timeline 보다 점점 벽으로 다가왔지만.. 그때까지도 할만 했다.
하지만 2.0이 나오면서 부터 기존에 onClick 형식으로 타임라인에 스크립트를 입력하던 방식에 한계가 오고 내입장에서는 듣도보도 못한 addEventListener 라는놈이 나오기 시작하면서.. "아.. 개발자의 영역으로 가버리는구나" 생각하고 디자인에만 매진하게 되었다.

역시 이것도 지금은 후회하는 중이다.. 지금 개발자로 전향할줄 알았다면 그때 좀 힘들어도 포기하지 않았을텐데 -ㅅ-
지금도 이벤트가 정확하게 동작하기 위해서 trace로 확인하는 테스트 과정을 거쳐야 원하는 대로 결과가 나오는등.. 언제나 조금 복잡한것은 삽질의 연속이다.

역시 이 글도 [2010/02/02 - [as3] - Flex, Flash 가비지 컬랙션 방법과 메모리 관리] 요넘 처럼 정리 차원에서 쓰게 되었고. 글을 쓰면서 사용하게될 예제들도 사용하기위해서 테스트 하던 소스들이 될것이다.


AS3 는 이벤트를 기반으로 동작하도록 되어있어서 모든 행위들이 이벤트를 발생하게 된다.
이벤트를 이해 하고 있어야 복잡한 동작들을 원하는 시점에서 원하는 방식으로 정확하게 동작할 수 있도록 구현이 가능하다.

이벤트를 사용하면서 얻는 이점

이벤트를 사용하면 특정 개체에 종속적이지 않은 프로그램을 만들 수 있다.
이전의 프로그래밍은 특정 행위가 발생했을때 콜백함수를 호출하는 방식이었다.
이런 방식은 해당 컴포넌트가 상위의 컴포넌트에 종속되는 결과를 가져온다. 상위 컴포넌트에 정의되어있는 함수를 호출하게 되기 때문에 다른 컴포넌트에서 사용할수가 없게 되고 사용하기 위해서는 같은 이름의 콜백함수를 등록해야 한다.
이런 방식은 각 컴포넌트들간의 결합도를 강하게 만든다.

이벤트를 사용하게 되면.. 하위컴포넌트가 발생시킨 이벤트를 상위 컴포넌트가 받을수 있고 하위 컴포넌트 입장에서는 이벤트만 발생하면 땡이다.. 상위에서 받아서 쓰던지 말던지 신경쓰지 않아도 되는것이다.
누가 받는지.. 어디서 받아서 무슨일을 하는지 전혀 신경쓰지 않아도 되기 때문에 여러곳에서 해당이벤트를 받아서 사용할수도 있고 다른 컴포넌트에 추가 되더라도 어차피 이벤트만 발생시키는 것이기 때문에 사용하는데 전혀 무리가 없다.

공용으로 사용할 수 있는 독립적인 컴포넌트를 만들 수 있게 되는것이다.

이벤트는 비동기적이다.
따라서 어떤 작업을 실행시켰을때 화면이 멈추지 않고 다른 작업을 진행할 수 있다.
이벤트가 완료되고 실행되는 핸들러에서 완료되는 시점에 해야 할일을 정의 해놓으면 되는 것이다.
이 방법은 반대로 불편하게 느껴지기도 하는데.. 순차적으로 처리 해야 하는 일이나.. 모든것보다 우선해서 뭔가를 처리 해야 할때 기존의 방식대로 처리 하다가 에러를 만나게 되는 경우가 많다.
하지만 제대로 사용한다면 자유로운 세계를 만나게 될 것이다.

AS3 에서 이벤트는 EventDispatcher 라는놈이 관리 하게 되고 이벤트 디스패쳐를 상속해서 만들어진 컴포넌트 들은 이벤트를 발생시키거나 받을 수 있다.
플렉스의 기본이 되는 UIComponent 도 이벤트 디스패처를 상속하고 있기 때문에 모든 컴포넌트들이 이벤트를 주고받을 수 있는것이다.

개요는 이정도로 마무리 지어도 될것 같고..

이후에 포스트들에서는



등에 대해서 알아 볼것이다.

저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 0


이 글은 자꾸 까먹어서 정리겸 이해하고 있는 수준에 맞게 풀어서 쓴 글이다..
-------------------------

Flash나 Flex의 메모리는 개발자가 그냥 지울수가 없게 되어있다.
자바도 마찬가지고 VM기반의 언어에서는 메모리를 할당하고 해제 하는 과정이 시스템에서 알아서 하도록 되어있기 때문에.. 언제 메모리가 해제 되는지 개발자가 컨트롤 할수가 없다.

개발을 한 프로그램을 돌리기 시작했는데.. 메모리가 사용할수록 증가 한다면 그 프로그램은 결국에 가서는 시스템에 문제를 일으키고 종료될 것이다.

메모리 관리는 Garbage Collector (이하 GC) 라는 놈이 하게 되는데 말그대로 쓰레기를 수거하는 역할이다.
더이상 프로그램에서 사용하지 않는 객체들을 초기화하고 메모리를 시스템으로 반환해주게 된다.

플레시 플레이어는 객체가 생성되면 시스템에 메모리를 요청하게 되는데 이때 이후에 생길 객체들을 위해서 객체의 메모리보다 더 많은 양을 할당 받게 된다.
이 메모리가 부족해지면 다시 시스템에 더 많은 메모리를 요구 하게 되는데 이때 GC 가 일을 하게 된다. 쓸모 없는게 있는지 찾고 있으면 지우고 부족분에 대한 메모리를 요청하게 되는것이다.

개발자가 removeChild 나 null 을 선언할때 메모리가 해제되지 않는다는것이 중요하다.

GC 가 돌면서 사용하지 않는 것을 찾는 방법은 두가지 룰이 있다.

1. 레퍼런스 카운팅 (Reference Counting)
2. 마크 앤 스윕 (Mark and Sweep)


레퍼런스 카운팅은 해당 객체가 참조하고 있거나 해당 객체를 참조하고 있는 놈이 있는지 찾는다. 해당 객체를 참조하고 있는 애들을 찾아서 있으면 카운트를 1 올리는 방식이다.

전부 찾아보고 나서 카운트가 0 인 객체들을 메모리에서 해제한다.

함수에서 Label 을 만든다

var label:Label = new Label();


new 키워드로 인스턴스를 생성했으니 메모리 공간을 할당 받는다. 하지만 참조하고 있는 곳이 없다. 따라서 GC 가 실행되면 label 은 메모리에서 사라진다.

라벨을 만들고 어플리케이션에 추가한다.

var label:Label = new Label();this.addChild(label);


함수 안에서 만들어졌지만 어플리케이션에 추가 되었다.

어플리케이션은 child 로 label 을 참조하고 있고, label은 parent로 어플리케이션을 참조하게 된다.

this.removeChild(label);


하게 되면 참조 관계가 사라지고 레퍼런스 카운팅 값이 0 이 되어 사라질수 있게 된다.

어플리케이션안에 캔버스를 만들고 캔버스 안에 라벨을 만든다.

var canvas:Canvas = new Canvas();this.addChild(canvas);var label:Label = new Label();canvas.addChild(label);


어플리케이션이 child로 캔버스를 참조하고 있고 label은 parent 로 참조하고 있으니 캔버스의 레퍼런스 카운팅은 2 이다.
라벨은 캔버스와 관계가 있으니 카운팅은 1 이된다.

이때 캔버스를 삭제한다.

this.removeChild(canvas);


어플리케이션에서는 캔버스가 사라지고 아무것도 없다. 과연 캔버스 객체는 메모리에서 사라질까?
화면에서 사라졌지만.  캔버스와 라벨은 여전히 레퍼런스 카운팅 값이 1 이다. 상호참조 하고 있기 때문에 레퍼런스 카운팅 기법만으로는 여전히 삭제가 되지 않는다.

이러한 상호참조 문제를 해결하기 위해서 사용되는 방법이 두번째의 마크 앤 스윕이다.

마크 앤 스윕 기법은 어플리케이션에서부터 하위로 참조되고 있는 객체들을 찾아서 마크한다. 어플리케이션에서 부터 참조를 체크 한다는 것이 중요하다.
쭉 마크를 하고 모든 뎁스에 대해서 마크가 끝나면 마크가 없는 애들은 지운다.
마크 앤 스윕 방법은 레퍼런스 카운팅 보다 작업하는 시간이 더 걸리고 시스템에 부하도 많이 주기 때문에 자주 실행되지는 않는다고 한다.

위의 캔버스는 어플리케이션에서 참조되고 있지 않기 때문에 메모리를 반환하고 생을 마감하게 된다.

중요한 것은 위의 방법을 이해하고 사용하지 않는 것을 삭제 할때에 다음번 GC가 삭제 된것을 전부 쓸어갈수 있도록 코딩을 해야 메모리가 무한정 증가하다가 뻗는것을 막을수 있다.

그럼 메모리를 반환하는데 있어서 걸림돌이 되는것들이 무엇이 있을까.
가장 문제가 되는 것이 이벤트 리스너다.

객체지향으로 설계 하다보니 이벤트를 엄청나게 사용하게 되고 addEventListener가 컴포넌트를 만들다 보면 대여섯개씩 기본으로 붙는 경우가 허다하다.

이벤트는 기본적으로 이벤트를 디스패치한 객체의 참조를 가지고 날아가게 된다.
따라서 event.target 또는 currentTarget 으로 이벤트를 발생시킨 놈을 사용할 수 있는것이다.

어떤 컴포넌트가 이벤트를 리슨 하거나 디스패치 하게되면 그 객체는 레퍼런스 카운팅이 1이상으로 유지 되기 때문에 살아있는 이벤트가 하나라도 있으면 삭제가 되지 않는 문제가 발생한다.

따라서 addEventListener 해준것은 반드시 removeEventListener 해주는 습관을 들여야 한다.

지워지는 시점이 명확하지 않다거나 내부에서 참조되서 관리가 힘들다거나 하는 경우에는 언제 remove 해줘야 하는지 결정하기가 쉽지 않다.
이럴때 사용하는것이 useWeakReference 이다.

addEventListener (type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
리스너에서 이벤트 알림을 받을 수 있도록 EventDispatcher 객체에 이벤트 리스너 객체를 등록합니다.

다섯번째 파라미터를 true 로 해주면 참조값을 약하게 잡고 있게 되고 이후에 GC 에서 삭제해줄 확률이 높아진다. 확률만 높아진다는 것이지 꼭 사라진다는건 아니기 때문에. removeEventListener 해주는 것이 가장 좋다.

이벤트쪽만 정리가 잘 되어있어도 메모리누수를 상당부분 막을수 있고.

플렉스IDE 를 사용한다면 개발중간중간에 프로파일러를 돌려서 체크 해보는 습관을 갖는게 좋을것같다.

나같은 경우는 커스텀 컴포넌트를 만들게 되면 destory() 함수를 만들어서 그 컴포넌트에서 사용되었던 이벤트 리스너를 일괄로 삭제하고 가능하면 컴포넌트 내부에 addChild 되어있던 것들도 삭제 해주는 함수를 만들어서 사용하고 있다.
removeChild 하기 전에 destory()를 실행시켜주고 삭제하면 기본적인 방지책은 되는것 같다.

PS. 메모리 관리에 좋은 방법들이 있으면 공유를 부탁드립니다~ 댓글 트랙백 환영
저작자 표시 비영리 동일 조건 변경 허락
신고

Comment +3

플렉스는 쓸만한 수준의 디버깅툴을 제공한다.
BreakPoint 를 사용해서도 작업을 할수 있고 Expression을 사용해서 특정 변수를 추적하는 것도 가능하다.

사용되는 함수를 전부 Step into 로 찾아들어갈 수도 있고 디버깅중에 BreakPoint를 추가할 수도 있다.

하지만 서버와 통신을 하는중에 발생하는 문제에 대해서는 정확하게 값이 넘어왔는데 플렉스쪽에서 처리를 잘못해서 데이터가 안나오는 것인지.
서버측의 문제인건지 명확하게 알기가 힘들다.


그래서 패킷을 감시하는 HttpWatch 라던지 서버쪽에 로그를 확인 한다던지 하게 되는데..
플렉스 콘솔에서 바로 확인할수 있는 방법도 있다.

1. <mx:TraceTarget /> 이라고 어플리케이션 아래에 적어준다..
2. 서버와 데이터통신을 시도한다..
3. IDE 하단의 View 탭의 Console 을 확인한다..


TraceTarget 을 적어놓기만 하면 http 통신이건 amf 소켓 통신이건 콘솔에 넘어온 데이터가 보이게 된다.


릴리즈 버전을 컴파일 할때는 주석처리 해주자..
저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 0

SharedObject를 간단하게 이야기 하면 웹브라우저의 쿠키와 비슷하게 개발자가 원하는 데이터를 로컬에 저장하는 객체이다.

개별 유저에 커스터마이징된 화면이라던지, 이전에 방문했었는지의 여부 라던지.. 개발자가 필요에 의해서 데이터를 저장해야 하는 경우에 사용할 수 있다.

쿠키는 String 데이터만을 가지는데 반해 SharedObject 는 Array, Object 등 복합데이터를 저장할 수 있기 때문에 활용가능성이 무궁무진하다.
(단 메서드는 저장할 수 없다 -ㅅ-)

기본 용량은 100K 이고 저장할 공간의 크기를 늘이거나 줄일 수 있다. 저장하는 데이터의 크기가 정해져 있다면 굳이 크게 할 필요는 없는거니 상황에 맞춰서 적용하면 되겠다.

100K를 넘는 용량을 지정하게 되면 사용자에게 저장하는 것을 허용할 것인지 여부를 묻는 대화상자가 나오게 되는데 아니오 해버리면 사용하지 못하는 상황이 와버리니 주의해서 사용하면 된다.

기본적으로 도메인 기준으로 공유할수 있다. 쿠키처럼 다른 도메인에서 만들어진 SO는 읽을수 없고 같은 도메인에서 만들어진 SO파일만 읽을 수 있다.

만들어지는 파일은 *.sol 확장자를 가지게 되고.. 저장되는 경로는 운영체제 시스템에 따라 다르고 윈도우의 경우는
C:/Document and Setting/계정이름/Application Data/Macromedia/FlashPlayer 하위에 저장이 된다.

var so:SharedObject = SharedObject.getLocal("mySo")
형식으로 불러와서 쓸수 있다
기본적으로 Object 처럼 key value 형식으로 저장을 하게 되고 data 속성을 통해서 내부의 값들을 가져올 수 있다.

공유객체를 읽어오도록 하면 SharedObject객체가 존재 할때는 data 를 읽어오고 데이터가 없으면 새로운 객체를 생성하게 된다.

간단하게 예제를 보면서 확인 해보자.




SharedObject 데이터가 있다면 userName 과 description 에 값이 나온다.
없는경우 왼쪽에서 값을 입력하고 createSo 버튼을 누르면 생성된다.

오른쪽에서 key 텍스트 필드에 "userName" 이나 "description", "rinn" 이라고 입력하고 getSO 버튼을 누르면 아래의 필드에 값이 표시된다.

리프레시 해보면 왼쪽 필드가 채워져서 swf가 로딩될것이다.

스크립트 부분의 소스이다.

import mx.controls.Alert;
private var so:SharedObject;

private function init():void
{
	so = SharedObject.getLocal("mySo");
	if(so.data.userName == undefined)
		Alert.show("ShareObject가 정의되어있지 않습니다");
	else
	{
		txtUserName.text = so.data.userName;
		txtDescription.text = so.data.description;
	}
}

private function createSo():void
{
	setSo("userName",txtUserName.text);
	setSo("description", txtDescription.text);
	
	var ar:Array = [];
	ar.push("http://rinn.kr");
	ar.push("rinn@naver.com");
	setSo("rinn", ar);
}

private function clearSo():void
{
	so.clear();
	txtUserName.text = txtDescription.text = "";
}

private function setSo(key:String, data:*):void
{
	so.data[key] = data;
}

private function getSo(key:String):*
{
	if(so.data[key] == undefined)
	{
		Alert.show(key+" 는 정의되어있지 않습니다");
	}
	return so.data[key];
}

createSo 함수에서 보면 저장할 수 있는 데이터가 여러가지 형식이 가능하기 때문에 활용범위가 넓다.

기본적으로 페이지의 이동이나 브라우저가 닫힐때 저장을 하게 되는데 필요할때 즉시 저장하기 위해서는 so.flush() 를 사용하면 된다.
삭제하기 위해서는 so.clear()를 사용한다.

더 자세한 메서드는 레퍼런스 (http://livedocs.adobe.com/flex/3/langref/flash/net/SharedObject.html)를 참조하면 된다.

저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 1

  • 참고

    SharedObject 생성이 안되면 so:SharedObject = SharedObject.getLocal("mySo", "/") 생성할때 뒤에 경로 "/"를 줘서 생성 해보세요~

대부분의 RIA 사이트는 느리다.
SWF 파일이 크고 왠지 플레시를 사용했으니 뭔가 가만히 있지 않고 움직여야 하지 않느냐 하는 요구 때문에 점점 파일은 커지고 로딩하는데 시간이 걸리게 된다.
HTML과 달리 일단 로딩하면 페이지 이동이 없다는 것으로 클라이언트를 설득하면서 넘어가게 되는데 RSL을 사용해서 다이어트를 해보자

RSL은 Runtime Shared Library의 약자이다.
말그대로 미리 라이브러리를 로드하고 그것을 사용하는것이 아니고 Runtime에 공유 라이브러리를 사용하겠다는 것인데.

이게 처음에는 좀 뜻이 모호하다는 생각이 들었다. 단편적으로 이미지나 컴포넌트 같은것을 따로 빼내놓고 그것을 가져다가 사용한다는 것으로 알고 있었던 것이다.

하지만 RSL은 프레임웍도 런타임에 로드 할수 있도록 해준다.

사용법은 간단하다.

플렉스프로젝트의 Property 에서 Flex Build Path 를 선택해서 살펴보면 상단에 콤보박스가 있다.

이것을 Merge into Code 에서 Runtime Shared Library(RSL)로 바꾼다.


이렇게만 해주면 일단 준비는 끝이다.. 바뀐것을 확인 하고 싶으면..

SDK의 framework.swc 를 살펴보자.


RSL URL 항목에 framework_3.4.0.9271.swz 라는 링크가 보인다.
이것이 공통프레임웍 부분이다.

Edit를 눌러서 살펴보면


Deployment paths에 두개의 파일이 등록되어있는것을 알수 있다.

이 두 파일은 실제로 하는 일이 같고 swz 확장자의 파일은 최신의 플레이어를 위한것이고 swf 는 swz를 지원하지 않는 플레이어를 위한 파일이다.

이렇게 생성된 파일은 웹브라우저가 아닌 플레이어에 캐시되고 이 파일은 Adobe에서 signed 된 파일이기 때문에 브라우저 캐시를 지워도 사라지지 않고 남게 된다.

다른 어플리케이션에서 RSL을 사용하는 경우 이 파일이 없으면 새로 다운을 받고 있으면 다운 받지 않고 있는 것을 사용하게 된다.

라이브러리 패스에 잡혀있는 다른 swc들.. ex) flex.swc 같은 경우도 RSL로 따로 뺄수 있고 라이브러리 프로젝트를 만들어서 커스텀 라이브러리 swc를 가지고 있는 경우에도 마찬가지로 RSL 로 사용할 수 있다.

중대형 프로젝트에서는 어플리케이션이 하나가 아니고 모듈 등으로 나눠져 있는 경우가 많기 때문에 RSL의 사용은 선택이 아닌 필수가 된다.

이때 약간 주의 해야 할 점이 있는데 이것은 아래의 용량 변화 표를 보고 이야기 해보자.

RSL 사용 전후 크기 변화 (단위 : KB)

   사용전  사용후
 index.swf  495  224
 serviceCreator.swf  702  283
 serviceManager.swf  349  97
 taskManager.swf  291  83
 serviceViewer.swf  637  138

공통 파일
framework_3.4.0.9271.swz   556
framework_3.4.0.9271.swf   553

위의 두개는 어플리케이션이고 아래의 세개는 모듈이다.
용량을 보면 거의 30% 정도로 크기가 줄어들었다. 
이때 주의 해야 할 점은 공통파일이 최소 한번 로딩되어야 한다는 것이다. 
일단 한번 로딩되고나면 클라이언트에 캐시로 잡히기 때문에 더이상은 신경쓰지 않아도 된다.

만약에 index.swf 만 사용한다면 로딩되어야 하는것은 495kb -> 224+556= 780k 로 오히려 늘어나게 된다. 
하지만 메뉴를 하나라도 불러서 사용하게 된다면 그때부터는 이득을 볼 수 있다. 

이 부분만 적용하고자 하는 프로젝트에서 확인하고 적용하면 될것이다.

아무리 인터넷 속도가 빨라졌다고 해도 RIA 사이트는 아무래도 다른 사이트보다 늦게 뜨게 된다. 기본 프레임웍을 RSL을 사용해서 로딩 부담을 줄이고 라이브러리 프로젝트를 사용해서 자주 사용되는 부분들만 따로 빼서 관리 하는것 만으로도 사용자의 부담을 훨씬 줄일수 있지 않을까 생각한다.

더 심도 있는 내용은
DieBuster  http://www.diebuster.com/?p=676  요쪽 히카님블로그에서 살펴보면 된다.
뭔가 레벨이 다른 분이라 오히려 적용보다는 참고만 하게 되는 블로그 -ㅅ-;

저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 1

ExternalInterface 세번째 입니다.

ExternalInterface가 뭔지 전혀 모르겠다 하시는 분은
2009/12/30 - [Flex/ExternalInterface] - ExternalInterface 기본기
이 포스트를 먼저 읽어 보고 오시면 됩니다.

자바스크립트에는 유용한 기능들이 많습니다.
가장 많이 사용하는 window 객체에는 브라우저의 정보 및 페이지 정보를 알아올수 있는 메서드들이 포함되어있는데 페이지 정보는 location에 들어있습니다. 그중 몇가지를 살펴보면 아래와 같습니다.

window.location.href
주로 페이지 이동시에 많이 사용했던 속성인데 저 자체로는 현재 페이지의 정보를 가지고 있습니다.

아무사이트나 들어간 후에 주소창에 javascript:window.location.href 라고 쓰게 되면 현재 페이지 주소가 나타납니다.
자바스크립트는 클라이언트에서 직접 실행되는 스크립트이기 때문에 기본 메서드 같은 경우 이런식으로 브라우저 주소창에 쓰면 대부분 실행됩니다.

window.location.hostname
페이지의 호스트 주소 정보를 반환합니다.

window.location.pathname
호스트 네임 뒤로 실제 페이지까지의 경로를 반환합니다.

window.location.search
주소 부분에서 get방식으로 넘어온 파라미터 부분을 반환합니다.
이게 중요합니다.
플렉스에서 get방식의 파라미터를 받아올때에도 이것을 사용합니다.

간단하게 예제를 봅시당.

주소 예제 : http://rinn.kr/post/aa.html?blogID=rinn&name=퍼플린

window.location.href : http://rinn.kr/post/aa.html?blogID=rinn&name=퍼플린
window.location.hostname : rinn.kr
window.location.pathname : /post/aa.html
window.location.search : ?blogID=rinn&name=퍼플린

딱 보면 뭘 어떻게 사용해야 할지 감이 오실꺼라 생각됩니다.

HTML 페이지나 플렉스 어플리케이션에서 새창으로 다른 어플리케이션을 띄우면서 파라미터를 넘겨줘야 하는 경우가 생기는 상황이 많이 발생합니다.
내부에 로드 하는 경우는 여러가지 방법으로 데이터를 교환 할수 있지만 브라우저 자체가 달라지는 경우 에는 좀 힘들게 됩니다.

플렉스에서 넘어온 파라미터를 받는 Application.application.parameters 같은 경우 flashVar 로 넘어오는 것만 받을수 있습니다.
따라서 플렉스의 swf 를 임베드 할때에 파라미터를 같이 세팅 해줘야 하고 자바스크립트로 배열을 미리 만들어놓는다거나 해서 받아오도록 처리했었습니다.
데이터가 많아지거나 가변적이거나 할 경우 이런 방법은 꽤나 버그를 유발할수 있는 소지가 많습니다.

직접 주소를 가져다가 그냥 짤라서 사용하기만 하면 되니 이쪽이 더 쉬울꺼라 생각됩니다.

어플리케이션간에 파라미터 이동을 나만 고민 하지는 않았겠지요.
당연합니다 구글에 이미 사용이 가능한 소스도 있습니다


public static function getParameterValue(key:String):String
{ 
	var value:String;
	var uparam:String = ExternalInterface.call("window.location.search.toString");
	
	if(uparam==null)
	{
    	return null;
    }
    var paramArray:ArrayCollection = new ArrayCollection(uparam.split('&'));
    for(var x:int=0; x-1)
    	{
    		value = (p.replace((key + '='), '')).replace('?','');
    		x=paramArray.length;
    	}
    }
    
    return value;
}
깔끔하게 키값으로 받아올수 있도록 구현되어있습니다.


ExternalInterface.call("window.location.search.toString");

이렇게 직접 호출한 놈을 가지고 파싱해서 키에 맞는 value 값을 리턴해줍니다.

아래의 소스는 key-value 의 object로 넘어온 놈들을 전부 리턴 해주는 함수 입니다.


public static function getAllParameters():Object
{
	var _params:Object = {};
	var uparam:String = ExternalInterface.call("window.location.search.toString");
	
	if(uparam==null)
	{
    	return null;
    }
	
	uparam = uparam.replace('?','');
	
	var params:Array = uparam.split('&');
	var length:uint = params.length;
	
	for (var i:uint=0,index:int=-1; i<length; i++) 
	{
		var kvPair:String = params[i];
		if((index = kvPair.indexOf("=")) > 0)
		{
			var key:String = kvPair.substring(0,index);
			var value:String = kvPair.substring(index+1);
			_params[key] = value;
		}
	}
	return _params;
}

이처럼 자바스크립트를 사용할수 있는 Externalinterface는 활용할수 있는 부분이 꽤 많습니다.
이 글을 보시게 되는 분들도 좋은 방법이 있으면 저한테도 공유좀 부탁드립니다 -ㅅ-;;;




ps.
전체를 가져오는 소스와 키로 받아오는 소스는 제작자가 다른 소스 입니다.
북마크를 날려먹은 관계로 원본 블로그 주소를 찾을수가 없군요.
이곳저곳에서 퍼다가 링크 걸어놓은 주소는 있는거 같은데.. 쩝;
아시는분은 댓글로 남겨주시면 제작자 블로그 링크를 추가 하도록 하겠습니다.

저작자 표시 비영리 동일 조건 변경 허락
신고

Comment +2

  • 트랙백 감사합니다. ExternalInterface를 이용해 JS의 API를 사용하는 것은 좋은 방법이긴 하지만 약점도 있습니다. 바로 웹브라우져에서 동작하지 않고 독립 Flash Player에서 동작하거나 AIR에서 동작하는 경우입니다. 이때는 ExternalInterface를 이용하는 것자체가 무의미합니다. 물론 반드시 웹브라우져에서 동작한다는 것을 가정한다면 상관없습니다. ^^

    • 브라우저에서만 가능 하다는 내용은 기본기쪽을 쓰면서 언급 하기는 했습니다.

      아무래도 작업 하는쪽이 웹쪽만 작업 하다보니 별 생각없이 사용하게 되는거 같어요 ㅎㅎ

ExternalInterface가 뭐하는건지 잘 모르는 분은
2009/12/30 - [Flex/ExternalInterface] - ExternalInterface 기본기  이 글을 보고 오면 됩니다.

ExternalInterface 가 자바스크립트의 함수를 실행시키기만 하는것이 아니고.

이전 글에 있듯이.

Externalinterface.call("window.alert('아싸~')");
처럼 자바스크립트 내장객체를 호출하거나 메서드를 실행하는것도 가능합니다.
이걸 이용해서 예전에 유행했던 윈도우 창 흔들기를 간단하게 구현해보도록 하겠습니다.



버튼을 클릭해보세요. 파일을 업로드 했습니다 ㅎㅎ

역시 아쉽게도 글쓰는 곳이 파일 업로드가 안되서 이 블로그를 흔드는것은 시범을 보여드릴수가 없고 어플리케이션 하나 만들어서 아래소스를 붙여넣기 하고 실행해보시면 됩니다.

import mx.controls.Alert;

private var timer:Timer;
private var dir:Boolean = false;
private var offsetX:int;
private var offsetY:int;

private function shakeWindow():void
{
	offsetX = int(Math.random() * 20);
	offsetY = int(Math.random() * 20);
	
	timer = new Timer(30, 10);
	timer.addEventListener(TimerEvent.TIMER, shakeIt);
	timer.addEventListener(TimerEvent.TIMER_COMPLETE, stopShake);
	timer.start();
}

private function shakeIt(e:TimerEvent):void
{
	if(dir)
	{
		offsetX = -offsetX;
		offsetY = -offsetY;
	}
	dir = !dir;
	ExternalInterface.call("window.moveBy("+offsetX+","+offsetY+")");
}

private function stopShake(e:TimerEvent):void
{
	timer.removeEventListener(TimerEvent.TIMER, shakeIt);
	timer.removeEventListener(TimerEvent.TIMER_COMPLETE, stopShake);
}

스크립트 블록은 이렇게 되고 버튼 하나 만들어서 shakeWindow()를 호출해주시면 됩니다.

자바스크립트의 window.moveBy(x,y) 함수는 현재의 윈도우 위치에서 x, y 만큼 윈도우를 이동시켜주는 함수 입니다.

간단하게 offset 값을 정해주고 해당 타이머가 돌아가는동안 윈도우를 움직인다.
이걸로 끝입니다.

간단한 것이 가능하다면 복잡한것도 가능합니다.

브라우저 쿠키를 AS 3.0 만으로 만들고 삭제하고 읽어들이고 할수도 있습니다.
AS3 에는 같은 기능을 하는 SharedObject가 있지만 프로젝트에 따라서 쿠키를 사용해야 하는 경우가 있는데 이런경우 html에 추가 해야 하는 불편 없이 추가 할수 있습니다.

이부분은 이미 잘 만들어진 것이 있기 때문에 따로 구현하지 않고 링크로만 대신합니다.


저 링크에서 보듯이 Externalinterface를 사용해서 뭘 할것이냐는 전적으로 아이디어에 달려있는것 같습니다.
그냥 간단하게 정보 확인용으로만 사용할수도 있고. javascript에서만 가능한것들과 연계해서 뭔가 훨씬 재밌는것들을 찾아낼수도 있지 않을까 싶습니다.


저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 0


ExternalInterface는 swf 파일을 싸고 있는 컨테이너 html 의 자바스크립트와 통신하기 위한 인터페이스 입니다.

ExternalInterface.call을 사용해서 html에 있는 자바스크립트 함수를 실행 시킬수 있고
ExternalInterface.callback을 사용해서 자바스크립트에서 SWF의 함수를 실행시킬수 있습니다.

이전 AS 2.0 에서는 fscommand()가 자바스크립트와의 통신에 사용되었는데 Player 9 버전 이후에는 Externalinterface를 사용하도록 권장하고 있습니다.

html과 함께 사용되는 것이기 때문에 swf만 실행시키거나 stand alone player에서 실행시키면 디버그 창을 만날수있습니다.

ExternalInterface가 중요한 이유가 C# 등 윈도우프로그램을 사용할경우 C#이 플레이어 api를 가지고 ExternalInterface를 구현해 놓으면 SWF와 윈도우 프로그램간의 통신 프로토콜로도 사용할수 있습니다.

addCallback(functionName:String, closure:Function):void
[정적] 컨테이너로부터 호출 가능하도록 ActionScript 메서드를 등록합니다.

functionName은 자바스크립트에서 플레시로 호출할때의 이름입니다. closure는 해당 이름을 플레시플레이어가 받았을때 호출할 함수 입니다.

addCallback 에서 String으로 키워드를 받고 그것에 closure에서 정의된 함수를 호출하는 구조이기 때문에 callback 에서 자바스크립트가 부르는 함수는 실제로 swf의 함수 이름이 아닐수도 있습니다.

콜백을 등록하기 전에 ExternalInterface.available을 사용해서 swf를 싸고 있는 컨테이너가 ExternalInterface를 지원 하는지 확인 후에 등록하는 것이 좋습니다.

call(functionName:String, ... arguments):*
[정적] 0개 이상의 인수를 전달하는 Flash Player 컨테이너에 의해 노출된 함수를 호출합니다.

call 함수는 자바스크립트의 함수 이름을 직접 지정하게 됩니다.
call 에서 부르는 함수는 실제 자바스크립트 함수의 이름이어야 합니다.

ExternalInterface.call 함수가 유용한 이유는 자바스크립트 함수를 단지 호출하는게 문제가 아니라 함수 실행 위치가 컨테이너로 옮겨간다는데 있습니다.

무슨소리냐 하면. functionName이 꼭 이름만 호출해야 할 필요가 없다는거죠. 저기에 html상에서 실행될수 있는 자바스크립트 함수가 직접 들어갈수 있습니다.

ExternalInterface.call("window.alert('아싸~')");
이렇게 하게 되면 Flex의 Alert 함수가 아닌 윈도우얼럿이 뜨게 됩니다.

Flex에서 IFrame 컴포넌트를 사용한다거나 하게 되면. 레이어가 플렉스보다 위쪽에 생기게 되어서 Flex Alert을 사용하게 되면 알람메시지가 IFrame컴포넌트보다 하위에 나와서 보이지 않게 되는데 이럴때 유용하게 사용할 수 있습니다.

자바스크립트 정리된 사이트가 갑자기 필요하게 되는 순간입니다.. -ㅅ-;;;

기본적인 내용은 여기서 마치고 다음 글에서 실제 이걸로 활용할수 있는 것들에 대해서 써보겠습니다.
ExternalInterface의 예제 들은 검색에 쳐보면 많이 나오기 때문에 패스 하도록 하겠습니다.

더큰 이유는 제가 이글을 쓰고있는곳이 파일첨부가 안됩니다..
보안프로그램과 방화벽때문에.. ㅠㅠ
부득이하게 이번 글은 예제 파일은 없이 갑니다 -ㅅ-~

Tip.

ExternalInterface는 동기로 동작하게 됩니다. 일반적인 플렉스 처럼 비동기가 아니고 콜백을 받거나 call을 하게 되면 플렉스함수가 실행되지 않고 멈추게 됩니다.
위에서 나온 alert을 띄우는것을 가지고 테스트 해보시면 됩니다.
Alert이 뜨는 순간 그 다음에 있는 플렉스 함수들은 실행되지 않습니다.

call을 호출하고 그 결과를 받을때에도 이벤트방식으로 동작하지 않기 때문에 결과가 올때까지 swf는 멈춰있게 됩니다. 테스트 해보시고 적용하실때 고민해서 적용하시는것이 자잘한 버그를 생산하지 않는 원동력이 됩니다..

다음 포스트에서는 응용편을 써볼까 합니다. 그럼..~
저작자 표시 비영리 동일 조건 변경 허락
신고

Comment 0