BLOG ARTICLE 전체 글 | 126 ARTICLE FOUND

  1. 2014.01.24 [Wowza] Client에서 Server함수호출, Server에서 Client함수호출
  2. 2014.01.24 [Wowza] NetConnection사용해서 서버연결하기
  3. 2014.01.09 [Wowza] WOWZA 설정하기 5
  4. 2013.12.18 [Wowza] 윈도우환경에서 WOWZA 설치하기
  5. 2013.12.06 [FlexExample] 모든 이벤트 리스너 가져오기
  6. 2013.12.05 ExternalInterface 사용시 Chrome에서 보안설정을 했음에도 A SecurityError occurred: Error #2060가 발생하는 문제
  7. 2013.12.04 PureMVC
  8. 2013.11.27 플래시플랫폼에서의 영상처리
  9. 2013.11.05 [WebRTC] WebRTC, 그리고 표준전쟁 1
  10. 2013.10.23 [FlashPlatform]Actionscript Reference 로컬파일로도 볼수 있었네요.
  11. 2013.10.22 [FlexExample] SWF 사이의 통신 (Passing data between SWFs)
  12. 2013.10.14 [FlexMobile] TextArea에서 스크롤 자동으로 넘기기
  13. 2013.10.11 [FlexMobile] 슬립모드 방지 및 앱 종료 2
  14. 2013.09.16 [FlexMobile] Session유지
  15. 2013.07.01 flashvars속성을 이용해서 JSP to FLEX Data Passing
  16. 2013.04.11 Apache와 Tomcat의 역할 12
  17. 2013.04.11 HTTPD (HyperText Transfer Protocol Daemon)란? 1
  18. 2013.02.23 creationComplete의 오해와 진실
  19. 2013.02.15 Flex Component의 삶 (Flex Component LifeCycle)
  20. 2013.02.12 Flex에서의 이벤트 흐름
  21. 2013.01.21 ActionScript에서 데이터 바인딩 정의(Defining data bindings in ActionScript)
  22. 2013.01.10 Flex, Actionscript의 Sprite클래스와 Shape클래스
  23. 2013.01.09 Flex, Actionscript 디스플레이 표시객체 구조
  24. 2013.01.09 Flex, Actionscript 에서 연관배열(associative array), Dictionary
  25. 2013.01.08 Flex의 ClassFactory
  26. 2013.01.04 Actionscript에서 array 속성
  27. 2013.01.02 ArrayList vs ArrayCollection
  28. 2013.01.02 ArrayCollection의 속성값으로 인덱스 구하기(how to get the index by ArrayCollection's property)
  29. 2012.12.21 [FlexExample] Mic활동 감지 및 이퀄라이저 만들기(Detecting Mic activity and Visualization)
  30. 2012.12.19 [FlexExample] Flex에서 MP3 재생시키기




* 예제실행을 위해서는 [Install-dir]/applications/Tutorial2가 정의되 있어야 하고, [Install-dir]/conf/Tutorial2/Application.xml 파일을 복사해 두어야 합니다. 그리고 Application.xml파일에 모듈설정을 해주셔야 합니다. 


* 서버측 모듈설정

 ...

<Module>

      <Name>Tutorial2</Name>

      <Description>Invoke function in ServerSide</Description>

      <Class>com.storyjava.Tutorial2</Class>

 </Module> 

 ...


* Client측 소스

 ...

 // Server에서 호출할 Client함수정의

 var obj:Object=new Object();

 obj.clientFunction = function(param:String):void

 {

     Cc.log(param);

 };


 nc.client=obj;

 nc.connect(address.text);

 ...


 // Server의 함수를 호출 함

 nc.call("serversideFunction"null"Hello Server!");

 ...

                           

* Server측 소스                   

 ...

 // Server측 함수, *접근제한자 public임에 유의

 public function serversideFunction(IClient client, RequestFunction function, AMFDataList params){

    client.call("clientFunction"null"Hello Client!");

 }

 ...

          

Tutorial2.fxp

Tutorial2.java


AND



아래 예제는 WOWZA미디어 서버에 연결테스트 하는 예제입니다.  자신의 미디어서버 주소를 넣으시고 연결해보세요~:) 서버에 연결하는 핵심코드는 아래와 같습니다. NetConnection객체를 하나 생성해주고, connect()함수로 서버에 연결합니다.


     ...

  /**

   *  서버에 연결한다. wowza설치폴더/applications/Tutorial1 폴더가 생성되 있어야함.

   */

  protected function onConnect(event:MouseEvent):void

  {

      nc=new NetConnection();

      nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);

      nc.connect(address.text);

   }

   ...


                                                            

Tutorial1.fxp

Tutorial1.java


[참조] AS3 NetConnection Reference

AND



1. WowzaMediaServer에서 Port설정 및 방화벽 설정


WOWZA는 스트리밍을 위해 아래의 포트를 사용합니다.  시작하기 앞서 필요한 포트를 방화벽설정을 해 두셔야 합니다.  기본적으로 모든 스트리밍은 TCP 포트 1935를 이용합니다.  참고로 다른 미디어서버(FMS, Red5등)들 또한 스트리밍 포트로 1935를 사용합니다. 표준이 있는것은 아닌것 같지만, 암묵적인 우리들만의 약속인듯 합니다. 


 TCP 1935

 RTMP/RTMPE/RTMPT/RTSP-interleaved streaming/WOWZ

 TCP 8084-8085

 JMX/JConsole monitoring and administration

 TCP 8086

 Administration 

 UDP 6970-9999 

 RTP UDP streaming


포트설정은 [install-dir]/conf/VHost.xml 에서 하며 당연한 이야기지만 다른 어플리케이션과 포트과 겹치지 않도록 주의가 필요합니다.  아래 테이블은 스트림에 사용되는 일반화되어 있는 포트들입니다.  따라서 다른 프로그램 설치시 아래 포트의 사용은 안하시는것을 추천드립니다.


 TCP 80

 Apple HTTP Live Streaming (Apple HLS) 

 Adobe HTTP Dynamic Streaming (Adobe HDS)

 Microsoft Smooth Streaming

 MPEG-DASH streaming

 RTMPT

 TCP 443

 RTMPS, HTTPS

 TCP 554

 RTSP




2. 로깅(Loggin)


WMS에서 로그관리는 Java프로그래밍에서 가장 널리 쓰이는 log4j 유틸을 사용합니다. WMS의 로그파일은 [install-dir]/logs 폴더안에 쌓입니다. 기본적으로 로그가 쌓이는 레벨은 대부분의 에러이슈를 모니터링 합니다.  에러에 대한 대처(troubleshoot)을 하실때는 debug로깅을 turn on 해주셔야 합니다. [install-dir]/conf/log4j.properties 파일을 여셔서 아래의 INFODEBUG로 바꾸신 후 작업을 하시면 됩니다.  반면 실서비스시에는 INFO 로그레벨을 사용하셔야 합니다. DEBUG로 했을 경우, 하드웨어 성능이 빵빵해도 쌓이는 로그파일은 감당하기 힘들 듯 합니다.  




3. 서버튜닝(Server tuning)


WMS에서 설정파일은 모두 XML파일로 되어있습니다. 모든 설정파일은 [install-dir]/conf에 위치하며, 서버가 시작할 때 아래의 설정파일들을 읽어옵니다. 따라서 아래의 내용을 수정했을 경우, 서버를 재시작하셔야만 수정사항이 적용됩니다.  설정에 관련된 내용은 도움말 Configuration Reference를 참조하시면 됩니다. 

하드웨어 리소스를 가장 적절하게 이용하기 위해서, 서버를 적절히 설정하는 것이 매우 중요합니다. WMS에서 기본적으로 설정되어 있는 값들은 어플리케이션개발에 있어서 최적의 환경을 제공합니다.  잘못된 설정으로 인해 하드웨어 리소스를 초과해버리면 서버는 애기치 못한 여러가지 문제를 야기시킬 수도 있습니다.

 성능튜닝에 관해 자세한 내용은 Performance Tuning 를 참조하세요.


 Server Configuration Files

 Server.xml

 일반적인 서버 설정 - 서버Address, 포트, JMX설정 등을 설정

 VHosts.xml

 가상호스트(Virtual hosts)에 대한 정의

 log4j.properties

 로그설정 - 로그를 남길 level, 경로등을 설정

 Virtual Host Configuration Files

 Authentication.xml

 RTSP와 HTTP 인증(authentication) 설정

 CEACaptionConversion.xml

 CEA-608 폐쇄캡션(Closed Caption) 설정

 DVR.xml

 nDVR 기본 설정

 HTTPStreamers.xml

 Cupertino(Apple HLS), Smooth(Smooth Streaming), San Jose(Adobe HDS) 스트림 설정

 LiveStreamPacketizers.xml

 HTTP packetization 설정

 LiveStreamTranscoders.xml 

 Transcoder 기본설정 

 MediaCasters.xml 

 MediaCaster restreaming 설정

 MediaReaders.xml 

 파일포멧 reader 설정

 MediaWriters.xml  파일포멧 writer 설정
 MP3Tags.xml 

 MP3 ID3 tag naming

 RTP.xml

 RTP와 MPEG-TS packetization 설정

 StartupStreams.xml 

 Streams started at virtual host startup

 Streams.xml  Stream type 설정
 TimedTextProviders.xml

 Closed-captioning 설정

 VHost.xml  Virtual host 설정
 VHosts.xml 

 Virtual hosts 설정

 Application Configuration Files Application.xml 

 Application 설정 




4. 관리 및 모니터링(Management and monitoring) - JMX and JConsole


WMS는 서버 관리와 모니터링을 위하 JMX(Java Management Extensions)와 JConsole을 사용합니다.


① WMS에서 JMX 사용하기

JMX인터페이스를 사용하려면 먼저 [install-dir]/conf/Server.xml 파일을 수정해 주셔야 합니다. <Enable>항목의 false를 true로 바꿔주시고, 서버가 로컬이 아니라면 <IpAddress>항목과 <RMIServerHostName>을 서버주소로 수정해주셔야합니다. 서버주소에는 IP주소뿐만 아니라, 도메인주소도 올 수가 있습니다.



만약 WMS가 NAT(Network Address Translation)를 거치게 된다면, <IpAddress>항목에는 내부아이피가, <RMIServerHostName>항목에는 외부IP가 와야 합니다. 저 또한 공유기의 NAT기능을 사용하고 있으므로 다음과 같이 설정하였습니다.


 


JMX설정 완료 후 서버를 재시작 하시고 [install-dir]/logs/wowzamediaserver_access.log 파일을 열어 보시면 JMX 바인딩이 시도된 것을 확인 하실 수 있습니다.


service:jmx:rmi://localhost:8084/jndi/rmi://localhost:8085/jmxrmi

-or-

service:jmx:rmi://[wowza-ip-address]:8084/jndi/rmi://[wowza-ip-address]:8085/jmxrmi



② WMS에서 JConsole 사용하기

JConsole은 Sun JDK에 기본적으로 포함되어 있는 유틸입니다. JDK가 설치된 폴더의 [java-install-dir]/bin/JConsole.exe에 위치해 있습니다.  윈도우 환경이시라면 시작메뉴를 통해서도 실행 하실 수 있습니다. local접속이나 remote접속을 하신 후 첫 화면은 아래 그림과 같이 CPU사용량과 Memory사용량을 실시간으로 나타내 주고 있습니다. 



MBeans탭에 WowzaMediaServerPro노드를 확장하면 JConsole과 JMX인터페이스를 통해 관리할 수 있는 항목들이 나타납니다.



모든 Wowza객체들이 디폴트로 포함되어있는 것은 아닙니다. [install-dir]/conf/Server.xml 파일에 <AdminInterface>태그영역에 보시면 모니터링 될 객체들을 설정하실 수 있습니다.  주석부분에 이용가능한 모든 객체리스트가 나와있습니다.



이 부분에서 특정 클라이언트나 미디어스트림 객체들을 등록해서 모니터링 할 수 있습니다. Server.xml파일을 수정하신 후에는 서버를 재시작 해주셔야합니다.

AND



Wowza Media Server(이하 WMS)는 Windows, Mac, Linux 모두 지원합니다. 이 글은 Windows7 64bit환경에서 JDK 64bit, WMS 3.5.2버전을설치하는 기본적인 안내서입니다.  32bit운영체제를 지원하지만, 되도록 64bit 운영체제 환경에서 64bit자바를 설치하시는 것을 권장합니다. 이는 최적의 퍼포먼스를 얻기위한 권장사항이며, 64bit환경과의 퍼포먼스 차이가 얼마나 되는지는 아직 경험해 보지 못했습니다. 


1. 자바설치



Java패키지는 3가지 형태로 분류되어 제공되고 있습니다. 아래 내용을 보시면 JDK가 JRE와 WMS에 사용할 모니터링 툴을 포함하고 있으므로 3가지 패키지중 JDK만 설치하시면 됩니다. Oracle홈페이지에 접속하셔서 JDK를 다운받으시고 설치를 하시면 됩니다.


 Java Development Kit(JDK) 

   JDK는 JRE를 포함하고 있습니다. 그리고 server-side 어플리케이션 개발과 디버깅을 할 수 있습니다. 또한 JConsole모니터링 툴을 포함하고 있습니다. JConsole은 JMX(Java Management Extensions)를 통해 로컬이나 원격지에 있는 서버를 관리하고 모니터링 하는 기능을 가지고 있습니다. 

 Java Server JRE

   Java프로그램을 개발버전이 아닌 실행버전 입니다. Windows 32-bit환경에서는 지원되지 않으며 JVM 모니터링 툴과, 서버어플리케이션에 필요한 기본적인 툴들을 포함하고 있습니다. 그리고 Java JRE와는 달리 브라우저위에서는 구동이 불가합니다.

 Java JRE

   32-bit JRE7버전부터는 WMS를 구동시킬 수 없습니다. 32-bit플랫폼에서 WMS를 실행하기 위해서는 Java Server JRE나 JDK를 설치하셔야 합니다.





2. 자바 환경변수설정


설치된 자바를 전역에서 사용하기 위해 환경변수를 설정해주셔야 합니다.


① 시스템(윈도우키+Pause Break) -> 고급 -> 환경변수 -> 시스템변수의 새로 만들기 -> 변수이름 : JAVA_HOME, 변수값 : Java설치경로 


② 시스템변수의 Path선택 -> 편집 -> 변수값에 ;%JAVA_HOME%; 추가


③ 콘솔창(윈도우키+R -> cmd)에서 Java -version으로 환경변수가 잘 잡혔는지 확인




3. 라이센스키 받기


WMS설치에 앞서 Wowza Media Server Trial버전의 라이센스 키를 받으셔야 합니다. Trial버전은 30일 사용기간 제한이 있지만, WOWZA에서 제공하는 유료 유틸리티들 또한 30일 동안은 무료로 이용하실 수 있습니다. 여기를 클릭하셔서 필요정보를 입력하시면 이메일로 Trial버전 시리얼넘버가 옵니다. 바로 답변이 오는 경우도 있지만, 길게는 20분까지 안오는 경우도 있었습니다. 그리고 30일이 지난 후 다시 재신청할 수 있으며 신청절차또한 같지만, wowza의 합격(?)을 받아야 라이센스키를 받으실 수 있습니다. 


 Release버전에 따라 라이센스키 형식이 조금 다릅니다. 각 버전에 따른 유효한 키가 있으며, 새로운 라이센스키를 발급받을 경우 가장 최신버전에 유효한 라이센스키를 받게됩니다. 따라서 새로받은 라이센스키를 최신버전이 아닌 WMS에 입력하면 설치는 되지만, 서버시작시 유효하지 않은 라이센스라 서버 시작이 되지 않습니다. 

라이센스키는 [Install-dir]/conf/Server.license 파일에 저장됩니다. 

* 위에서 언급한 유료 유틸들은 WMS에 추가적으로 더해지는 형태로 설치가 되기때문에 AddOn이라 불리는데,  TranscoderAddOn, nDVRAddOn, DRMAddOn등 여러가지 AddOn들이 있습니다.





4. Wowza Media Server설치


Wowza Media Store 통해 WMS를 받으실 수 있으며, 설치과정은 Next만 클릭하면 되고, 설치시작시 메일로 받은 라이센스키를 입력하셔야 합니다.

그리고 Windows64bit환경에서 Transcoder AddOn을 설치하실 분들은 .NET Framework 3.5.1 과 Desktop Experience를 설치하셔야 합니다.  .NET Framework 3.5.1은 다운받아 설치하시는 것이 아니라 Windows운영체제에서 기본적으로 제공하는 것이므로 아래 그림과 같이 설치를 하셔야 합니다.  참고로 Windows 8.1에서는 서버를 설치 후, 서버시작을 해보니 알아서 설치를 진행해 주더군요.






5. 설치확인


①  시작프로그램에서 살펴보기

시작프로그램을 확인해보시면 아래그림과 같은 구조로 되어있습니다.  서버시작/정지, JConsole, Documentation, 예제 등이 포함되어 있는 것을 알 수 있습니다. 특히 Documentation을 눈여겨 보셔야 하는데, 이곳에는 WMS에 대한 메뉴얼들이 있습니다. 이글을 쓰는 저또한 이를 참조하여 글을 쓰고 있습니다.


 

② 탐색기에서 폴더구조 살펴보기

설치된 WMS폴더를 열어보면 다음과 같은 구조로 되어있습니다. 



각 폴더의 역할을 간략하게 살펴보면 다음과 같습니다.

 applications

 서버 어플리케이션이 위치하게 되는 폴더입니다.

 bin

 서버관련 유틸리티들을 모아둔 폴더입니다.  

 conf

 서버 설정에 관련된 모든 파일이 있습니다. 

 content

 컨텐츠를 담아두는 폴더입니다. 물론 경로변경 가능합니다.

 documentation

 WMS문서를 모아둔 폴더입니다.

 examples WMS에서 기본적으로 제공하고있는 예제파일들이 있습니다.
 keys

 

 legal License관련 세부적 설명과, 관련 문서들이 있습니다.
 lib

 WowzaIDE로 모듈을 만들어 저장하면, 이 폴더에 .jar파일로 저장됩니다.

 lib-native

 

 logs

 log파일들이 쌓이는 곳입니다. 이 폴더또한 설정을 통해 경로변경이 가능합니다.

 transcoder 



③ 서버시작  

시작-> Wowza Startup을 선택하면 3가지 액션을 확인하실 수 있습니다. 

  1. Windows 보안 경고 가 뜨는데, 액세스 허용을 해줍니다.
  2. Wowza Media Server3 콘솔창이 열립니다.  서버에 대한 전반적인 정보가 출력됩니다. 서버 상황에 따른 실시간 모니터링이 되므로 작업이 자주보게 될 화면입니다.
  3. 스트리밍하는 기본샘플페이지가 열립니다. 정상적으로 설치되었다면 Start버튼을 클릭하면 영상이 재생될 것입니다.


④ 브라우저창에서 빌드넘버 확인해보기

브라우져 창에 http://[wowza-ip-address]:1935 로 접속하시면 아래의 같이 WOWZA버전을과 빌드넘버를 뿌려줍니다. 만약 이 화면이 나오지 않으신분은 보안설정을 체크해보시길 바랍니다.


⑤ 간단한 주문형 비디오(VOD, Video On Demand) 예제파일 테스트

[install-dir]/examples/VideoOnDemandStreaming/FlashRTMPPlayer/player.html 을 실행하시고, Connect하면 간단한 주문형비디오 스트리밍 테스트를 할 수 있습니다.  영상이 나온다면 성공적으로 설치된겁니다.



6. WOWZA에서 제공하는 예제들 둘러보기


 WOWZA는 초보가 시작하기 쉽도록 다양한 훌륭한 예제들을 제공하고 있습니다. [install-dir]/examples에 위치해 있으며 7가지 예제를 제공하고 있습니다.



예제를 테스트 하기 전 install.bat를 통해 설치를 먼저 하셔야합니다. install.bat 파일을 실행시키면 설치완료가 완료됩니다.  엄밀히 말해 '설치'라고 하기보다는 예제가 구동가능하도록 설정을 변경해주는 것입니다. 설치가 완료되면 콘솔창이 하나 뜨는 것 이외에는 별다른 반응은 없으며, README.html파일을 실행시키면 다양한 예제 목록들이 나오고, 간단한 클릭만으로 예제들을 경험해 보실 수 있습니다.



7. WOWZA IDE


1. Standalone 형태로 설치


- 다운로드 링크 : Windows InstallationMac OS X Installation


 * JDK 64bit버전을 설치하신 분들은 Wowza IDE 2 를 실행하기 위해서는 JRE 32bit를 설치 하셔야 합니다. 그렇지 않으면 아래와 같이 실행이 되지 않습니다.



2. Eclipse IDE 형태로 설치


- Eclipse 3.5(galileo) 이상부터 설치

- Location : http://wowza.com/wowzaide2

AND


현재 추가된 이벤트 리스트를 가져오는 예제입니다. 

[소스] MonkeyPatchTest.fxp

[출처] http://dougmccune.com/blog/2008/02/21/monkey-patching-flexsprite-to-list-all-event-listeners-on-any-flex-component/

AND


1. A SecurityError occurred: Error #2060 에러의 원인


SWF <-> JS 간의 통신을 하기위해 ExternalInterface.call 을 사용하는데, 보안설정을 해줬음에도 유독 Chrome에서만 security error가 발생하였습니다. 분명 보안설정까지 깔끔하게 해 주었고, 다른 브라우져(IE, FireFox, Safari)에서 테스트를 해보아도 아무 이상없이 잘 돌아갔었습니다.  문제발생의 원인은 Chrome에서 swf파일을 읽어올때 쓰이는 Flash Player가 두개가 설치가 되어있었습니다. 


* 주소창에 chrome://plugins/ 


두개가 설치된것은 현재(2013.12) Chrome에서 쓰이는 Plug-in기술은 두가지가 있는데, 두가지 모두의 형태로 설치가 되어있었습니다.



2. Chrome의 Plug-in 모델 PPAPI(Pepper API), 그리고 NPAPI(Netscape Plugin API)


그렇다면 왜 Chrome은 Plug-in 기술을 두가지를 쓰고 있을까요? 그 이유는 바로 Plug-in기술이 과도기에 있기 때문입니다. 

현재(2013.12) 가장 널리 쓰이고 있는 Plug-in아키텍쳐는 NPAPI라는 기술입니다.  하지만 NPAPI는 구Netscape가 만든 것으로 낡은 기술이라, Google은 새로운 Plug-in의 필요성을 느끼게되었고 Adobe와 손을잡고 만든것이 바로 PPAPI입니다.   그리고 2013년 9월, 구글은 크롬에서 NPAPI는 2014년중에 중단하겠다고 발표하였고, 모질라 FireFox에서도 PPAPI가 지원이 될 예정입니다. 그리고 당연히 Flash Player도 PPAPI형태로 설치가 가능합니다.

[참고] NPAPI WIKIPEDIA : http://en.wikipedia.org/wiki/NPAPI



3. 그럼 현재 PPAPI를 지원하지 않는 브라우저는?


PPAPI를 다른 브라우져에서 사용하려면 pepper.js라는 놈을 사용하면 됩니다. pepper.js는 Emscripten를 이용해서 pepperAPI를 Chrome뿐만 아니라 Firefox, Internet Explorer, Safari 등 대부분의 브라우져에서 사용할 수 있게하는 자바스크립트 라이브러리입니다.    다만, 현재(2013.12) 한참 개발중이라 버그가 있을 수도 있다고 하네요.    

[참고] http://trypepperjs.appspot.com/



4. 해결방안


보안설정을 똑바로 하셨다면, PPAPI방식으로 설치된 Flash Player를 끄면 에러없이 잘 됩니다.  

그런데 문제는 고객들의 Complain.... OTL   



[참고] 구글 크롬 플로그인 지원 중단과 어도비 플래시 - 열이아빠님의 글 : http://koko8829.tistory.com/1383

AND

PureMVC

Adobe Platform/Flex 2013. 12. 4. 14:03


[이미지 출처] http://puremvc.org/


1.  PureMVC란?

MVC(Model-View-Controller) 디자인 패턴을 기반으로 Application 만들때 사용하는 Framework 입니다. Actionscript3로 만들어진 오픈소스이고, 무료입니다. Flex, Flash, AIR 지원합니다.  Standard 버전과 MultiCore 버전 두가지가 있습니다.


2. PureMVC Standard version

The Model, View and Controller application tiers are represented by three Singletons (a class of which only one instance may be created).

The MVC Singletons maintain named caches of Proxies, Mediators and Commands, respectively. The Facade, also a Singleton, provides a single interface for communications throughout the application. These four Singletons are referred to as the Core Actors.

Data objects, be they local or remote, are managed by Proxies.

The View Components that make up the User Interface are managed by Mediators.

Commands may interact with Proxies, Mediators, as well as trigger or execute other Commands.

All actors discover and communicate with each other via the Facade, rather than work directly with Model, View and Controller.

PureMVC also introduces a Publish/subscribe-style Observer notification scheme. This allows asynchronous, event-driven communications between the actors of the system, and also promotes a loose coupling between those actors, since the subscriber never needs to have direct knowledge of the publisher.

The Standard Version Reference Implementation is written in ActionScript 3.


3. PureMVC MultiCore version

This variation supports modular programming, allowing the use of independent program modules each with their own independent PureMVC 'Core'. A Core is a set of the four main actors used in the Standard framework (Model, View, Controller and Facade). This version of the framework uses Multitons instead of Singletons. Rather than storing a single instance of the class, a Multiton stores a map of instances. Each Core is referenced by an associated Multiton Key.

The MultiCore Version of the framework was developed due to the widespread need for modular support in a world of ever-more ambitious Rich Internet Applications which must load and unload large pieces of functionality at runtime. For instance a PDA application might need to dynamically load and unload modules for managing task list, calendar, email, contacts, and files. The "multicore" version facilitates unit testing.

The MultiCore Version Reference Implementation is written in ActionScript 3.


[출처] http://en.wikipedia.org/wiki/PureMVC

[참고1] pureMVC 알아보기 :  http://flystone.tistory.com/29

[참고2] pureMVC 체험 : http://blog.naver.com/zoom7810?Redirect=Log&logNo=50032401652

[참고3] PureMVC에 대한 단상 : http://blog.naver.com/hiddenid?Redirect=Log&logNo=40057116343

[참고4] PureMVC 프레임워크를 이용한 MVC 예제 : http://blog.jidolstar.com/328

[참고5] PureMVC UML로 표현 : http://chaospace.tistory.com/3

[참고6] http://www.dehats.com/drupal/?q=node/36

AND


Flash기반으로 웹캠을 통해 객체추적(Object Tracking)을 해야 할 일이 생겨, 자료수집한 내용을 정리해봤습니다.  얼굴인식은 '영상처리' 혹은 Computer Vision이라는 전문 분야가 있었고, 저는 이 분야에 관해 지식이 전무한 상태에서 자료수집을 한 내용입니다. 그래서 잘못된 정보가 있을 수 있으니 참고하시고 읽어주시길 바람니다. 잘못된 정보에 관한 지적은 언제든지 환영입니다.^^

* Object Tracking : 웹영상에서 특정 부분을 추적하는 행위. 예를들면 얼굴의 눈을 찾는다던지, 입을 찾는 행위.


1. 영상처리(Computer Vision)


영상처리를 하는 기술인 OpenCV는 가장 널리 쓰이고 있으며, 이를통해 QR코드, Bar코드, 얼굴인식(Face Recognition), 증강현실(AR, Augmented Reality) 등의 기반이 되는 기술입니다.   OpenCV는 C로 만들어져있으며 Windows, Linux, Max, Android, iOS를 지원합니다.  

* OpenCV : http://opencv.org/


2. 용어정리


자료수집을 하면서 용어의 의미를 몰라 어려움이 많았습니다. 영상처리분에서 기본적인 용어정리를 해봤습니다. 이 분야 종사자가 아니라도 기본 교양으로 알고계시면 좋을 듯 합니다.


* 공개소스 컴퓨터 비전 (Open Source Computer Vision) : 인텔사의 실시간 컴퓨터 영상 프로그램 라이브러리. 공개 소스 컴퓨터 비전(Open CV) 코드는 객체ㆍ얼굴ㆍ행동 인식, 독순(讀脣:입술 읽기), 모션 추적 등의 응용 프로그램에서 사용된다. 컴퓨터가 인간처럼 입체적으로 볼 수 있도록 만들 수 있는 소프트웨어로 많은 이미지 기능을 포함한 도구 박스가 행동 인식, 사물 추적, 얼굴 인식 등을 포함하는 컴퓨터 비전 응용 프로그램 개발을 지원한다.

[출처] http://terms.naver.com/entry.nhn?docId=863371&cid=2636&categoryId=2636


OpenCV(Open Computer Vision) : OpenCV(Open Computer Vision)은 오픈 소스 컴퓨터 비전 C 라이브러리이다. 원래는 인텔이 개발하였다. 윈도, 리눅스 등의 여러 플랫폼에서 사용할 수 있다. 실시간 이미지 프로세싱에 중점을 둔 라이브러리이다. 인텔 CPU에서 사용되는 경우 속도의 향상을 볼 수 있는 Intel Performance Primitives (IPP)를 지원한다.

[출처] http://ko.wikipedia.org/wiki/OpenCV



안면 인식 시스템(facial recognition system) : 안면 인식 시스템(facial recognition system)은 디지털 이미지를 통해 각 사람을 자동으로 식별하는 컴퓨터 지원 응용 프로그램을 말한다. 이는 살아 있는 이미지에 나타나는 선택된 얼굴 특징과 안면 데이터베이스를 서로 비교함으로써 이루어진다.

이는 일반적으로 보안 시스템으로 사용되며 지문이나 동공 인식 시스템과 같은 다른 생체 인식(biometrics)과 비교될 수 있다.

[출처] http://ko.wikipedia.org/wiki/%EC%95%88%EB%A9%B4_%EC%9D%B8%EC%8B%9D



* 화자 인식(Speaker Recognition) : 화자 인식(Speaker Recognition)은 입력 받은 음성 데이터를 미리 저장된 데이터베이스와 비교하여 화자가 누군인지 식별하는 기술을 말한다. 음성 인식 분야의 가장 어려운 분야 중 하나이며, 이론상으로는 완벽한 식별은 불가능하다고 알려져 있다. 음성 인식 보안 솔루션에 많이 가장 많이 응용되고 있다.

[출처] http://ko.wikipedia.org/wiki/%ED%99%94%EC%9E%90_%EC%9D%B8%EC%8B%9D



FERET(Facial Recognition Technology) : FERET 데이터베이스는 안면 인식 시스템 평가의 사실상 표준이다. 안면 인식 기술(FERET) 프로그램은 미국 방위고등연구계획국(DARPA)과 국립표준기술연구소(NIST)가 관리하고 있다. 안면상의 데이터베이스는 1993년 12월부터 1996년 8월 사이에 수집되었다. 2003년 DARPA에서 이들 안면상의 고해상도, 24비트 컬러 버전을 내놓았다. 시험된 데이터세트는 856명의 개인을 대표하는 2,413의 정지 안면상을 포함한다.

FERET 프로그램은 조지 메이슨 대학교의 알고리즘 개발자 해리 웩슬러 박사가 이 데이터베이스의 수집을 감독하도록 선택된 것과 별개로 수집되는 대량의 안면상 데이터베이스를 수립하기 시작했다. 데이터베이스 수집은 웩슬러 박사와 필립스 박사의 공동 노력이었다.

--> 얼굴 인식률 테스트 할 때 사용.

[출처] http://ko.wikipedia.org/wiki/FERET_%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4


AAM (Active Appearance Model)

Shape 정보와 Texture 정보를 이용하여 통계적인 방법으로 학습하여 얼굴의 윤곽을 찾는 방법.

AAM 방법은 Active Shape Model (ASM) 방식을 개선한 방법으로 AAM(Active Appearance Model)은 기존 ASM의 물체의 형태 정보와 물체의 텍스쳐 정보를 이용하여 이미지내의 물체를 찾는 방법이다. 이 방법은 물체의 형태 정보와 텍스쳐 정보를 이용하여 물체의 형태를 유지하면서 학습된 텍스쳐 정보를 기반으로 가장 유사한 텍스쳐를 가지는 부분을 검색하여 보다 정확하게 물체의 형태 및 위치를 찾을 수 있도록 한다. 하지만 이미지내의 텍스쳐 정보는 방대하여 찾고자 하는 물체의 이미지 크기에 따라 연산속도에 영향을 미치게 된다.

[출처] http://blog.naver.com/kpetera?Redirect=Log&logNo=70145198734




3. 객체추적(Object Tracking)


웹캠 영상의 얼굴에서 실시간으로 눈을 추적하는 방법은 어떻게 구현이 될까요?  대략적인 방법은 눈 위치에 대한 Data를 xml파일에 저장시켜 놓습니다. 그리고 이 Data를 기반으로 실시간 영상을 분석해서 눈을 추적합니다.  이는 수학적 알고리즘이 기반이 되고, 여러가지 방법들이 있고, 많은 논문들이 나와있습니다.  


* 얼굴 화상 검색 시스템 및 얼굴 화상 검색 방법 : http://cctvnews.co.kr/atl/view.asp?a_id=2004

* 얼굴인식 - 특징점 추출 : http://bluelimn.tistory.com/entry/%EC%96%BC%EA%B5%B4%EC%9D%B8%EC%8B%9D-%ED%8A%B9%EC%A7%95%EC%A0%90-%EC%B6%94%EC%B6%9C

* Motion detection 알고리즘 : http://blog.naver.com/PostView.nhn?blogId=mhk807&logNo=150027154743&redirect=Dlog&widgetTypeCall=true

* 홍채인식기술 : http://www.yhj.pe.kr/iris/what_is_iris_recognition.htm

* 유료 솔루션 : http://www.luxand.com/facesdk/

* OpenCV Haar/cascade training 튜토리얼 : http://darkpgmr.tistory.com/70

* ★얼굴인식 라이브러리 링크 모음 : http://blog.mashape.com/post/53379410412/list-of-50-face-detection-recognition-apis


4. Java에서 OpenCV


OpenCV를 Java에서 사용하기 위한 라이브러리입니다. 하지만 퍼포먼스 문제로 많이 쓰이지 않고 있습니다.

https://code.google.com/p/javacv/

* JavaCV설치 : 




5. Flash에서 영상처리 

 Flash에서의 영상처리는 어떻게 할까요? 기본적으로 영상Data를 Bitmap으로 받아와서, 이 Data를 기반으로 영상처리를 합니다. 아직 소스분석을 해보지 않아 어떠한 원리로 동작되는지는 파악이 안되고, 수집한 예제를 남깁니다.  


* 참고1 : http://www.adobe.com/mena_fr/devnet/flash/articles/webcam_motion.html

* 참고2 : http://www.brianhadaway.com/getting-started-with-flash-webcam-motion-tracking/

* 참고3 : https://github.com/chinchang/AS3-Motion-Tracker

* 손으로 그림페이지 넘기는 예제 : http://www.position-relative.net/creation/gesture/

* 손 추적하는 예제 : http://nocreativity.com/blog/webcam-motion-detection-coolness

* AIR OpenCV Extension : https://github.com/wouterverweirder/AIR-OpenCV-Extension


위의 예제들은 BitmapDataAPI만으로 구현된 예제들이라 입맛대로의 영상처리는 외부 프레임워크를 쓰지 않는 이상 구현에 어려움이 많을 것으로 판단하여 Flash플랫폼에 돌아가는 프레임워크를 찾아보니 Marilena라는 오픈소스 프로젝트가 있었습니다.


6. Marilena


Ohtsuka Masakazu 라는 일본 개발자가 OpenCV를 Actionscript에서 이용하기 위해 만든 것.  Spark Project 의 code네임 Marilena라고 불림.


* Marilena Source Code : https://code.google.com/p/face-recognition-library-as3/downloads/list

* AS3 libraries for face detection 링크모음 : http://www.flexflashforum.com/viewtopic.php?f=5&t=1085

* 예제1 : http://blog.inspirit.ru/?p=416  

* 예제2 : http://www.quasimondo.com/archives/000687.php 

* 예제3 : http://www.francois-tarlier.com/blog/tag/marilena/


 









* 필독서 : http://book.naver.com/bookdb/book_detail.nhn?bid=6702518

* 대표 커뮤니티 : http://cafe.naver.com/opencv 

* deface(Actionscript 3 visual object detection/tracking) : https://code.google.com/p/deface/

* Computer Vision 동영상 강의(영문) : http://videolectures.net/Top/Computer_Science/Computer_Vision/

* FACE RECOGNITION HOMEPAGE : http://www.face-rec.org/




 

 

AND


개인적으로는 Flash기반 다자간 화상회의 프로젝트를 오랜기간 해왔으나, WebRTC로 구현된 화상회의(Google의 Hangout)를 보면 WebRTC의 놀라운 기술에 좌절감을 느끼기도 합니다.   뿐만 아니라 Flash 프로젝트는 Flash Player위에서 돌아간다는 태생적 한계를 가지고 있는반면, WebRTC는 표준이죠.  차세대 기술, 아니 어쩌면 이미 대세의 기술임이 틀림이 없죠.  많은 기업들이 이미 WebRTC를 활용한 제품들을 내놓고 있습니다.  Flex개발자이지만 Flash에 대해서는 회의적일수 밖에 없는 흐름이네요. 


 

WebRTC기술에 대한 기업동향 및 주요사건들을 시간순서로 정리해 보았습니다. 이글을 쓰고있는 지금(2013.11.06)으로 부터 내일 WebRTC표준코덱이 정해지게 되는데, 과연 승자는 Google진영이 될지, 아니면 MS가 될지 너무 궁금하네요.


  • WebRTC란?
    RTC는 Real-Time Communications의 준말로, Javascript API와 HTML5를 이용해서 실시간 미디어통신을 가능하게 하는 기술입니다.  이는 Third-party프로그램이나 plug-in없이 브라우져만으로 화상채팅이 가능하게 합니다. 



1. WebRTC의 탄생


WebRTC는 Google Hangouts 엔지니어 팀에서 생겨났다고 합니다. 그들이 처음 plugin형태로 비디오채팅 서비스 할때, plugin없이 브라우져만으로 비디오,음성을 통신할 수 있는 기술이 없을까 하는 생각을 하게되는데 이때 만들어진 기술이 WebRTC라 할 수 있겠네요.  Google은 WebRTC의 설계단계에서 부터 표준화를 염두해 두고 프로젝트를 시작하게 됩니다.



2. Google의 On2 인수 (2010.02) 

표준화를 위해 개선된 비디오코덱과 오디오 엔진이 필요성을 느끼고, Google은 2010년초 On2사를 $125m에 인수하게 됩니다.  On2사는 강력한 비디오 코덱 'VP8' 코덱기술을 가지고 있는 회사였죠. 인수하자마자 Google는 WebRTC와 HTML5의 비디오테그에 코덱을 사용하기위해 VP7, VP8을 오픈소스화 시켜버립니다. 

관련글 - Google to Acquire On2 Technologies

             Google Taketh Away

 


3. Google의 GIPS 인수(2010.05.07)

Google은 스웨덴회사인 GIPS도 $68m에 인수하게 됩니다. GIPS는 최고의 voice엔진기술을 가지고 있었죠. 2010년에만해도 Google은 WebRTC를 위해 $200m 투자를 합니다.  

 관련글 - Google to make cash offer to acquire Global IP Solutions

 


4. Google, 'WebM' 프로젝트 런칭 (2010.05.19)


Google I/O Conference행사에서 비디오코덱 오픈소스 프로젝트인 WebM이 런칭됩니다.   'WebM' 프로젝트의 핵심은 VP8코덱이고, 로열티 없는 무료코덱을 지향합니다. 성능또한 H.264에 비해 떨어지지 않아 H.264을 지지하는 MS같은 회사들에게는 반가운 소식이 되지는 못합니다.







5. IETF(국제인터넷표준화기구) 표준화 착수 (2011.04) 

IETF RTCWeb Working Group가 만들어지고, WebRTC에 사용될 프로토콜을 표준화 시키는 작업이 본격적으로 시작됩니다.  


6. W3C 표준화 착수 (2011.05)

W3C WebRTC Working Group가 만들어지고, 여기서 각 브라우져사에게 줄 표준화된 APIs를 만들기 시작합니다.


7. Google의 전면전 선언 (2011)

Chrome의 'H.264지원 중단' 이라는 폭탄선언을 합니다. 이는 자사의 VP9을 밀기위한 특단의 조치였습니다.


8. Microsoft의 대응, Skype인수 (2011.05)

VP8를 싫어하는 MS는 이러한 Google의 행보의 대응이 흥미롭습니다. 초기 Microsoft는 Lync라는 오디오,비디오 및 화상회의 서비스가 있었지만, Apple의 FaceTime과 Google의 Hangouts에 밀려있었죠.  이에 Skype를 85억달러에 인수합니다. 이는 Microsoft가 생긴이래 가장 큰 규모의 인수합병이라 합니다.  Skype는 6억 6000만명의 가입자를 확보하고 있었니 엄청난 무기를 손에 넣은셈이죠.



Microsoft는 2012년까지 WebRTC에 소극적인 대응하지만, WebRTC의 엄청난 흐름에 MS가 대응을 안할수 없죠. 이에 CU-RTC-Web(웹기반 실시간커뮤니케이션) 라는 자신들만의 스펙을 W3C에 제안하게됩니다.  이 스펙을 따르게되는 브라우져는 plug-in 없이 skype를 이용할 수 있을지도...



9. Google, Hangouts 720p 서비스 시작 (2013.08)

Google의 Hangouts은 VIdyo에 유료코덱을 구입해 사용해 왔습니다. 하지만 이를 버리고 자사 코덱인 V8으로 전환하면서 720p화질 서비스를 시작합니다. 


10. Google, Chrome에 VP9코덱 탑제


11. Cisco가 던진 승부수, H.264 바이너리모듈 공개, 오픈소스화 (2013.10)

  Google의 Hangouts에서 사용했던 H.264코덱을 버리고, 자사의 VP8를 탑제하면서 720p화질서비스를 시작했습니다. 두달 후, 그리고 WebRTC에서 사용할 표준코덱을 정할 IETF의 88차 회의를 보름정도 앞두고 있는 시점에, 시스코는 자사의 핵심코덱인 H.264를 오픈해버립니다. 이는 Google에 돌직구를 날린 꼴입니다. 많은 하드웨어들이 H.264코덱을 사용하고 있고, 구글의 VP8은 호환성에 문제가 있다는 지적을 하고있습니다.  VP8을 지지해오던 모질라가 VP8뿐만아니라, H.264 또한 적극 지지하고 나섰습니다.

(Apple, MS, H.264) vs (Google, Mozila, Opera, VP8) 이런 구도였는데,  모질라가 양다리를 거치게 된것이죠.

 시스코입장에서는 MPEG LA에 로열티를 지불하면서 까지 이러는 이유는 표준코덱이 되기위한 마지막 핵펀치라 할 수 있겠습니다. 

관련글 - 동영상 코덱 시장에 때아닌 시스코 태풍

 


12. IETF, WebRTC를 위한 표준코덱 결정(2013.11.07)

   

관련글

* MS-구글, 화상채팅 기술 '웹표준화' 맞불 - http://www.zdnet.co.kr/news/news_view.asp?artice_id=20120808173629&type=det

* Adobe to support VP8 format in the Flash Player - http://blog.ericd.net/2010/05/19/adobe-to-support-vp8-format-in-the-flash-player/

* 기업용 화상회의 서비스 5종 '전격 비교' - http://www.ciokorea.com/news/10054

* 동영상 협업을 재정의할 3대 기술 : H265, 4K, WebRTC - http://www.ciokorea.com/news/16191

* 어도비, 플래시 잊고 HTML5로 '새출발' - http://www.zdnet.co.kr/news/news_view.asp?artice_id=20121116182609


AND

 

* 여기를 클릭하시면 다운받으실 수 있습니다.  왜 이럴 지금 알았을까.. ㅠ

 

이제 reference볼때 웹에서 오래 기다릴 필요가 없겠네요. ㅎㅎ

AND

 

SWF파일끼리 통신하는 예제입니다. 

 

* 보내는쪽

<?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="initConn()"

                   >

    

     <fx:Script>

           <![CDATA[

                import flash.net.LocalConnection;

               

                private var conn:LocalConnection;

               

                private function initConn():void

                {  

                     btnSend.addEventListener(MouseEvent.CLICK, sendMessage);  

                     conn = new LocalConnection();      

                     conn.addEventListener(StatusEvent.STATUS, onStatus);   

                } 

               

                private function sendMessage(event:MouseEvent):void

                {    

                     conn.send("taskConnection", "localconnectionHandler", inputTask.text);      

                }       

               

                private function onStatus(event:StatusEvent):void

                {     

                     switch (event.level)

                     {          

                           case "status":             

                                labelStatus.text = "LocalConnection.send() succeeded"; 

                                break;             

                           case "error":           

                                labelStatus.text = "LocalConnection.send() failed";                

                                break;    

                     }   

                }

           ]]>

     </fx:Script>

    

     <mx:Panel horizontalCenter="0" verticalCenter="0">      

           <mx:Form width="100%" height="100%" horizontalCenter="0" verticalCenter="0"> 

                <mx:FormItem label="Enter Task">              

                     <mx:TextInput id="inputTask"/>           

                </mx:FormItem>         

                <mx:FormItem label="Send Task ">        

                     <mx:Button id="btnSend" label="Send"/>  

                </mx:FormItem>           

                <mx:ControlBar> 

                     <mx:Label id="labelStatus" text=""/>      

                </mx:ControlBar>       

           </mx:Form>  

     </mx:Panel>

</s:Application>

 

* 받는쪽

<?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="InitConn()"

                   >    

     <fx:Script>

           <![CDATA[

                import flash.net.LocalConnection;      

               

                private var conn:LocalConnection;   

               

                private function InitConn():void

                {  

                     conn = new LocalConnection();   

                     conn.client = this;             

                     try {                

                           conn.connect("taskConnection");    

                     } catch (error:ArgumentError) {       

                           trace("Can't connect.");       

                     }         

                }         

               

                public function localconnectionHandler(msg:String):void

                {   

                     textareaTasks.text= textareaTasks.text + msg + "\n";   

                }           

               

                private function clearTasks(event:MouseEvent):void

                {              

                     textareaTasks.text="";      

                }

           ]]>

     </fx:Script>

    

     <mx:Panel  horizontalCenter="0"       

                   verticalCenter="0.5"    

                   verticalGap="15"     

                   paddingLeft="20"

                   paddingRight="20"

                   paddingBottom="20"

                   paddingTop="20"    

                   height="300"

                   width="500"

                   >      

           <mx:Label text="Your tasks are..."/>   

           <mx:TextArea id="textareaTasks"        

                            top="20" left="20" right="20" bottom="20"  

                            width="100%" height="100%"/>  

           <mx:HBox>         

                <mx:Button id="btnClearTasks" click="clearTasks(event)" label="Clear Tasks"/>  

           </mx:HBox>  

     </mx:Panel>

</s:Application>

http://blog.yoz.sk/2010/08/the-ultimate-guide-to-localconnection-swf-to-air/

AND

 

 


TextArea의 스크롤을 자동으로 넘기는 예제입니다. 

 

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

<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"

           xmlns:s="library://ns.adobe.com/flex/spark">

     <fx:Script>

           <![CDATA[

                import spark.components.supportClasses.StyleableTextField;

               

                private var num:Number = 1;

               

                private function inputText():void

                {

                     StyleableTextField(messageBox.textDisplay).htmlText += "<font>" + num.toString() + "</font>\n"; 

                     messageBox.selectRange(int.MAX_VALUE, int.MAX_VALUE);

                     num++;

                }

           ]]>

     </fx:Script>

    

    

     <s:VGroup width="100%" height="100%">

           <s:TextArea id="messageBox"

                           skinClass="spark.skins.mobile.TextAreaSkin"

                           width="100%" height="100%"

                           />

           <s:Button label="Input Text" click="inputText()"/>

     </s:VGroup>

</s:View>


AND

 

앱 개발에 앞서 항상 다음 두가지를 먼저 작업을 해놓고, 개발에 들어가는게 여러모로 좋을 것 같습니다.

 

1. 슬립모드에 들어가는 것을 방지하자.

2. 앱 종료시 앱을 완전히 종료시키도록 하자. 

 

대부분 기본적으로 슬립모드(화면자동꺼짐)기능을 사용하고 계실것입니다. 디바이스에 앱 테스트 할 때 슬립모드 방지기능을 해놓지 않으면 화면이 자꾸 꺼져버려서 개발에 불편함이 있을 수도 있으니, 이를 미리 막아놓고 개발하시는것을 추천드립니다. 그리고 어떠한 경로로 종료가 되든(강제종료,전화,슬립모드 등) 앱이 비활성화(deactivate)되면 앱을 완전히 종료시켜야 베터리도 작게 잡아먹습니다.  예전에 이 기능을 구현해놓지않아, 2GB데이터 용량을 하루아침에 다 써버린 경우도 있었습니다. 종료된줄만 알았던 개발앱이 계속 통신을 하고 있었더랬죠. ㅠ

 

먼저 Manifest설정을 해주어야 합니다. 프로젝트 생성시에 아래와 같이 DISABLE_KEYGUARD, WAKE_LOCK 설정을 체크하던지, 아니면 설정파일에 주석을 제거해주시면 됩니다.

문서에 보면 이 권한에 대한 설명을 다음과 같습니다.

 

DISABLE_KEYGUARD, WAKE_LOCK : 응용 프로그램에서 장치가 SystemIdleMode 클래스 설정을 사용하여 대기 모드로 들어가지 못하게 할 수 있도록 허용합니다.

 

 

 

 

 

 

 

 

코드를 보시면 다음과 같습니다.  코드설명을 구지 필요없을듯...

 

    protected function viewnavigatorapplication1_preinitializeHandler(event:FlexEvent):void

    {

         if(Capabilities.cpuArchitecture=="ARM")

         {

            NativeApplication.nativeApplication.addEventListener(Event.ACTIVATE, handleActivate, false, 0, true);

            NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE, handleDeactivate, false, 0, true);

            NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, onInvoke, false, 0, true);

         }

    }

               

    private function handleActivate(e:Event):void

    {

         trace("앱활성화");

         // 항상 AWAKE되게 설정

         NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;

    }

               

    private function handleDeactivate(e:Event):void

    {

         trace("앱꺼짐");

         // 앱종료시킴

         NativeApplication.nativeApplication.exit();

    }

               

    private function onInvoke(e:InvokeEvent):void

    {

         NativeApplication.nativeApplication.removeEventListener(InvokeEvent.INVOKE, onInvoke);

    }             

 

* Source code : WakeExample.fxp

* Flex Mobile에서 Manifest 설정 : Android 설정

AND


 


어떠한 앱이든 실행 중 전화가 오면,  실행중인 앱은 차단됩니다.   일반적으로는 사용자들은 차단된 앱은 다시실행되고, 예전상태 그대로 복구될꺼라 생각합니다. 이를 위해서 유지메커니즘(persistence mechanism)은  이러한것을 가능하게 하는데,  Flex프레임워크에서는 두가지 방법을 제공하고 있습니다.  

 

1. 메모리(In-memory persistence)상에 view상태를 저장하는 방법

2. 세션(Session persistence)을 이용해 상태를 저장하는 방법

 

실행되는 앱은 Mobile OS에 의해 언제든 종료가 가능하므로, 세션유지를 시키는 것은 매우 중요한 요소입니다.

 

1. In-memory persistence

 

Flex모바일 앱에서 화면에 보여지는 컨테이너 개념인 View는 data라는 속성으로 메모리상에 상태를 유지시킬 수 있습니다. 섹션이 바뀔 때, 현재 View의 data는 자동으로 저장되지만, 새로운 View가 ViewNavigator스택 메모리상에 올라가게 되는 경우는 현재의 view는 파괴됩니다. data 속성은 view가 다시 활성화 되면 예전의 data속성을 복구시킬 수 있습니다. 따라서 data속성을 사용하면 실행중 상태정보를 유지시킬 수 있습니다.

 

 

2. Session persistence

 

In-memory persistence가 앱이 실행 중, view사이의 상태에따라 data를 유지시키는 방법이라고 하면, Session persistence는 앱의 종료후에도 상태를 저장할 수 있습니다.   ViewNavigatorApplication ,  TabbedViewNavigatorApplication 컨테이너는 persistNavigatorState라는 속성이 있는데, 이 값은 true로 주면 상태를 유지할 수 있습니다. 기본값은 false로 설정되어 있습니다.  persistNavigatorState을 true로 주면 FxAppCache라는 캐시영역에 로컬공유객체(local shared object)가 저장됩니다. 로컬공유객체에 더 많은 정보를 담고 싶으시면  spark.managers.PersistenceManager의 메소드를 이용하시면 됩니다.

 

ViewNavigator session persistence

ViewNavigator컨테이너는 앱이 종료될 때에도 view스택의 상태를 저장함으로써 세션을 유지할 수 있습니다. 또한 현재view의 Data또한 저장이 가능합니다.  앱이 재실행될 때, ViewNavigator의 스택은 다시 복구가 되면서 종료되는 시점에서의 화면을 그대로 보실 수 있습니다. 왜냐하면 스택은 각 View에 대한 Data를 포함하고 있기때문에 view가 활성화 될때 다시 복구될 수 있습니다.

 

TabbedViewNavigator session persistence

TabbedViewNavigator 컨테이너에서의 세션유지는 종료되는 시점에서의 선택되어진 탭을 저장하고 있습니다. 탭 역시 ViewNavigator과 같이, view스택에 현재view의 Data와 함께 현재 view의 상태를 저장합니다.  따라서 앱이 재실행 될 때, 종료되는 시점에서의 활성화 된 탭과 연관되어있는 ViewNavigator가 복구됩니다.  여기서 주의하실점은 TabbedViewNavigatorApplication컨테이너로 정의된 앱의 경우 오직 현재의 View만 저장이 됩니다. 따라서 선택되어지지 않은 다른 View들은 저장이 안됩니다.

 

Session persistence data representation

Flex에서의 사용되는 persistence mechanism은 암호화 되지 않습니다. 그러므로 저장되어 있는 data는 다른 프로그램이나 사용자로부터 해킹당할수도 있습니다. 따라서 개인정보나 보안이 필요한 Data는 이 메커니즘을 사용하면 안됩니다. 보안된 자체 persistence manager를 선택적으로 사용할 수는 있습니다. 여기에 대한 더 자세한 정보는 Customize the persistence mechanism로 가시면 됩니다.

 

참고 : Enable persistence in a mobile application

AND

 

AND


 

1. 개념

 

사용자가 브라우져를 통해 네이버에 접속한다고 한다면, 브라우져 주소표시줄에 http://naver.com 라고 치면 됩니다.  사용자가 브라우져를 통해 네이버에 접속하는 이 행위는 "내가 네이버에 접속해요~" 라고 네이버 서버에 요청하는 행위입니다. 그리고 통상 사용자를 클라이언트라 칭합니다. 즉 클라이언트(사용자)는 서버(네이버서버)에 어떤것을 요청을 하게 되면 서버는 클라이언트의 요청을 받아들입니다. 그리고 서버는 클라이언트의 요청을 해석합니다.  클라이언트가 원하는 Data를 요청한 클라이언트에게 보내고, 클라이언트는 원하는 화면을 볼 수 있게 됩니다. 사용자와 서버, 둘 사이에 통신을 가능하게 하는 프로그램이 바로 브라우져인 것입니다.  브라우져는 사용자가 서버에게 어떠한것은 요청할 수 있게 하고, 서버에서 응답하면 브라우져는 응답받은 Data를 컴파일을 통해 사용자에게 뿌려줍니다.  그리고 이러한 구조를 흔히 CS(Client-Sever)라 부릅니다.

 

웹서버라는 것은 서버에서 클라이언트의 요청을 기다리고, 요청이 오면 받아들이고, 그 요청의 Data를 보내는 프로그램입니다.  이때 보내는 Data는 정적인 Data(html, css, js, image)로 한정합니다. 정적이라는 것을 쉽게 말하면 접속할 때 마다 변하기 않고 똑같은 Data만 보낸다는 것입니다.  (네이버가 정적이라면 네이버 접속할때 마다 똑같은 페이지를 보게되겠죠~?)

 

그렇다면 동적인 Data를 보내는 서버는 무엇일까요? 그 역할을 하는것이 WAS(Web Application Server)입니다. 통상적으로 컨테이너(Container), 웹컨테이너(Web Container) 혹은 서블릿 컨터에너(Servlet Container)라 부릅니다. 혹은 '와스'라 부르기도 합니다.

 

하지만 개발자가 아닌 사람들이 보통 일상적으로 말할때, "웹서버, 서버, WAS, 컨테이너, 서블릿" 등등을 구분하지 않고, 그냥 웹서버라 부릅니다.  그래서 처음 이 개념을 접하면 혼동이 올 수 있습니다.

 

웹서버로 가장 많이 쓰는 프로그램은 Apache사의 Apache, MS의 IIS등이 있습니다. WAS로 많이 쓰는 프로그램은 Apache사의 Apache Tomcat입니다.

 

2. Apache사의 Apache vs Apache사의 Apache Tomcat

 





Apache와 Apache Tomcat은 엄연히 다른 프로그램 입니다.  그리고 햇갈리기 쉬운게.... Apache랑 Tomcat 두개 프로그램을 합쳐놓아서 Apache Tomcat이라 부르느냐? 땡! 아닙니다!

 

Apache Tomcat = Apache + Tomcat  X

 

Tomcat을 그냥 Tomcat 이라고 하면 되지, 왜 사람 햇깔리게 Apache Tomcat이라고 하느냐!?  제가 생각하는 첫번째 이유는, Apache 재단에서 만든 프로젝트 이름이라 Apache Tomcat 붙이고 두번째 이유는 Tomcat에서 Apache의 기능(웹서비스데몬, Httpd)을 포함하고 있기 때문입니다.  하지만 Tomcat이 Apache의 모든기능을 포함하고 있는 것은 아닙니다. 이름때문에 혼동 마시길...   통상적으로 Apache Tomcat을 Tomcat으로 불리고, Apache는 그냥 Apache라 부릅니다.

 

Apache Tomcat = Tomcat의 WAS기능 + Apache의 웹서비스데몬기능

 

3. 성능향상을 위해 서비스 할 때 둘 다 설치를 해서, Apache는 웹서버 역할을 하게하고 Tomcat은 WAS 역할을 하게 한다는데여?

 

많이들 그렇게 쓰시지만 '성능향상이 된다' 라는 명제의 결론부터 말씀드리면 땡! 틀렸습니다. 그건 쌍팔년도 시대의 말이고, 똑똑한 아파치 개발자 형들이 업그레이드를 시켜놓아서 웹서버로 Tomcat 하나만 설치하여도 성능에 큰 차이가 없다 합니다. 토비님의 글을 보면 톰캣 5.5부터 Httpd의 native 모듈을 사용하기 때문에 동적인 페이지 뿐만 아니라, 정적페이지또한 처리가 가능해졌다고 합니다. 그리고 똑같은 엔진을 사용하기 때문에 성능상의 차이가 없다고 합니다.

'HTML > About Web' 카테고리의 다른 글

HTTPD (HyperText Transfer Protocol Daemon)란?  (1) 2013.04.11
Connection Pooling  (0) 2012.04.13
CGI(Common Gateway Interface)와 Servlet  (0) 2012.04.09
서블릿(Servlet)이란?  (0) 2012.04.06
AND




1. 웹 서버 소프트웨어의 총칭으로 HTTP 액세스에 대응하기 위한 소프트웨어. 「d」는 daemon(데몬;유닉스의 상주 프로그램의 일종)의 d. 중요한 것으로 CERN httpd, NCSA httpd, Netscape Netsite나 NCSA httpd 호환의 Apache 등이 있다.

[출처] 네이버용어사전

 

 

2. httpd란 HTTP Protocol을 지원하는 daemon이란 말입니다. HTTP Protocol이란 통신규약중 하나로서 브라우저에서해독가능한 파일, 즉 HTML 파일을 전송해주는 규약입니다.  마찬가지로 FTP를 지원하는 daemon은 ftpd이며, telnet을 지원하는 daemon은 telnetd 입니다. httpd란 다른말로 http를 지원하는 서버라 할 수 있으며, 우리가 흔히 Web Server를 구축한다는 말은 좁은뜻으로 httpd를 수행시킨다는 말과 같습니다. 현재 전세계적으로 가장 많이 사용되는 httpd로는 apache이며, 이는 Open Source로 제공하기 때문에 Linux의 기본 httpd입니다. 그 외에 Microsoft사가 만든 IIS가 있습니다. 한때는 Microsoft사의 Web Server도 Apache로 구동하여 IIS 사용자의 빈축을 산 적도 있습니다만 현재 Web Service용 httpd의 양대 산맥이라 할 수 있습니다.

[출처] 네이버지식in


'HTML > About Web' 카테고리의 다른 글

Apache와 Tomcat의 역할  (12) 2013.04.11
Connection Pooling  (0) 2012.04.13
CGI(Common Gateway Interface)와 Servlet  (0) 2012.04.09
서블릿(Servlet)이란?  (0) 2012.04.06
AND

 

지금까지 수백번 creationComplete라는놈은 그냥 써 왔지만, 그 진정한 의미를 모르고 그냥 써왔습니다. 그냥 어플리케이션이 실행될 때 creationComplete이벤트가 발생 됐을 때 처리하는 함수인줄로만 알고 있었습니다. 

아니.... 사실 creationComplete가 이벤트라는 사실도 못랐습니다. 그냥 MXML테그 속성으로, 테그가 실행될 때 발생하는 이벤트로만 알고있었습니다.  

 

 Flex LifeCycle을 공부하면서  테메테르님의 강의를 듣던 중 creationComplete에 대해 아주 명쾌하게 설명해주신 것을 정리해봤습니다.

 

creationComplete이라는 놈을 이해하기 위해서는 먼저 MXML이 컴파일 되면 ActionScript코드로 변환된다는 것을 아셔야 합니다. 즉, Flex는 원천은 ActionScript입니다. 다른 말로는 Flex는 하나의 ActionScript Framework이라고도 할 수 있죠.  어떻게 아냐구요? 증명해 볼까요?

 

① 먼저 'Example'이라는 이름의 프로젝트를 하나 생성하겠습니다. 생성 후 Package Explorer에서 Example 프로젝트를 선택하시고, 오른쪽버튼을 클릭하여 속성에 들어갑니다.

 

 

② 속성 들어가시면 Flex Compiler의 Additional compiler arguments부분에 컴파일 기본 옵션값으로 '-locale en_US' 라고 되어있습니다. 여기에 -keep-generated-actionscript 옵션을 추가합니다. actionscript코드를 유지한다는 옵션입니다.

 

 

③ bin-debug폴더에 보시면 generated라는 폴더가 생기고 여기에 Example-generated.as 파일이 생기는 것을 확인하실 수 있습니다.

 

 

④ 파일을 열어보시면, MXML 어플리케이션 이름이 actionscript 클래스 이름으로 되어있고, Application클래스를 상속받고 있는 것을 알 수 있습니다. 이와 같이 모든 MXML은 actionscript로 컴파일 된다는 것을 확인하실 수 있습니다.

 

 

 

⑤ 증명이 끝났으니 다시 creationComplete이벤트로 돌아가서, MXML에 다음과 같이 작성하고 Example-generated.as 파일을 보시면 creationComplete라는 이벤트가 추가되었음을 확인하실 수 있습니다. 그리고 컴파일러가 자동으로 리스너함수를 만드네요~ 그 함수안에 init()가 들어있습니다. 이 말인 즉, MXML테그의 creationComplete="init()" 의 의미는 "creationComplete이벤트가 발생 됐을 때 처리하는 함수" 의 의미가 아니라 creationComplete이벤트가 발생됐을 때 처리하는 함수는 MXML에서 자동으로 만들어 주고 init()는 컴파일러가 자동으로 만든 함수안의 하나의 문장일 뿐입니다.

참고사항으로 this.addEventListener("creationComplete", ___Example_Application1_creationComplete); 에서 ___Example_Application1_creationComplete의 의미는 ___Example_Application1_creationComplete함수의 시작주소번지를 기억하고 있는 상수값입니다. 함수이름이 아닙니다!

 

 

 

정리하면 5가지 Point로 요약이 되네요~

 

1. 모든 MXML파일이 컴파일 되면 actionscript코드로 바뀐다.

2. 프로젝트 컴파일 속성 옵션을 변경하면, 컴파일된 actionscript코드를 확인할 수 있다.

3. 테그의 속성으로 이벤트가 올 수 있다.

4. 테그에 creationComplete 속성으로 이벤트를 발생시키면 컴파일러가 자동으로 리스너함수를 생성해준다.

5. addEventListener("TMP", Test); 에서 Test는 Test라는 함수의 시작주소번지를 가지고 있는 상수값이다. 

AND

** 작성중인 글인데 귀차니즘으로 글 완성이 안되고 있어여. ㅠㅠ 라이프사이클은 파도파도 끝이 없네여 ㅡ,.ㅡ

 

Flex에서 제공하는 Panel은 기본적으로 동적기능(크기변경, 이동, 최대화 등)이 없습니다. 그러므로 동적인Panel을 만들려면 Panel을 커스터마이징(Customizing)을 해야합니다. 

기본 Panel에 동적인 기능 몇개를 추가하는데 알아야하는 것이 많았기 때문에 하나하나 정리해보았습니다.  이 포스팅의 최종목표는 UIComponent의 LifeCycle을 이해하고, 아래의 기능을 추가한 Custom Panel을 구현하는 것입니다.  초보 개발자인 만큼 이 포스팅의 잘못된 점이나, 부족한 점 등 어떠한 feedback도 환영합니다.

 

이 포스팅의 최종 목표는 Flex의 LifeCycle을 이해하고, 이를 바탕으로 다음의 커스텀패널을 구현하는데 있습니다.

 

1. 패널을 이동(Draggable)시킬 수 있다.

2. 패널의 크기를 변경(Resizable)할 수 있다.

3. 패널의 최대화(Maximize)버튼을 넣어 최대화 시킬 수 있다.

4. 패널의 최소화(Minimize)버튼을 넣어 최소화 시킬 수 있다.

 

 

 

1. UIComponent

 

 

그림과 같이 컨테이너나, 컴포넌트 등 Flex에서의 컴포넌트는 UIComponent의 자식들입니다.  따라서 어떠한 컴포넌트를 커스터마이징 하기 위해서는 반드시 UIComponent를 상속받아야 합니다. 하지만 커스터마이징하고싶은 컴포넌트를 상속받는게 일반적인 방법입니다. (모든 컴포넌트는 UIComponent를 상속받으므로)

 

 

 

 

 

 

 

 

 

                         UIComponent 계층구조(UIComponent Hierarchy)

 

 

UIComponent는 플렉스의 컴포넌트의 베이스가 되는 컴포넌트다. 플렉스 기본 컴포넌트의 기능을 추가 또는 수정할 목적이 아니라 완전히 새로운 컴포넌트를 만들고자 한다면 UIComponent를 상속해야 한다. UIComponent는 플렉스에서 화면을 효율적으로 랜더링하기 위한 여러 가지 알고리즘이 적용돼 있어 초기화부터 화면 렌더링, 화면상태 변경 등 라이프사이클에 해당하는 이벤트가 발생하고 콜백 함수를 호출한다. 옥고수

 

UIComponent 클래스는 모든 대화형(interactive) 및 비대화형(noninteractive) 시각적 구성 요소의 기본 클래스입니다. 대화형 구성 요소는 키보드 또는 마우스 작업 등의 사용자 입력을 받는 구성 요소로 정의됩니다. 사용자 상호 작용에 응답하지 않습니다. 예를 들어 ProgressBar 및 UILoader 구성 요소는 비대화형 구성 요소입니다.

대화형 구성 요소는 마우스 및 키보드 장치 입력과 같은 낮은 수준의 이벤트를 인식할비대화형 구성 요소는 데이터를 표시하는 데 사용되며  수 있으므로 탭 및 화살표 키를 사용하여 대화형 구성 요소로 포커스를 이동할 수 있습니다. 또한 마우스 및 키보드 입력을 받을 수 없도록 대화형 구성 요소를 비활성화할 수도 있습니다.http://livedocs.adobe.com/flash/9.0_kr/ActionScriptLangRefV3/

The UIComponent class is the base class for all visual components, both interactive and noninteractive.
An interactive component can participate in tabbing and other kinds of keyboard focus manipulation, accept low-level events like keyboard and mouse input, and be disabled so that it does not receive keyboard and mouse input. This is in contrast to noninteractive components, like Label and ProgressBar, which simply display contents and are not manipulated by the user.

 

 

 

 

 

 

 

2. Component LifeCycle

 

인간들의 삶의 과정을 보면  탄생-성장-성숙-죽음 이라는 사이클속에 우리는 살고 있습니다.  한사람의 인생을 알려면 어느 부모에게서 어떻게, 언제 탄생했는지, 어떻게 성장하고 또 어떻게 성숙되어 지는지, 그리고 언제 죽음을 맞이하는지 알아야 합니다.  Flex 컴포넌트의 삶 또한 인간의 삶과 매우 닮아 있습니다.  

Flex의 컴포넌트들은 일정한 규칙의 과정속에 탄생과 소멸이 됩니다. 흔히 그것을 두고 라이프사이클(LifeCycle)이라 칭합니다. 

 

왜 이런 일정한 규칙에 의해 탄생과 소멸이 되도록 설계되었을까요? 이유는 성능향상을 위해서입니다. 일정한 규칙을 정해놓음으로써 반복되는 작업을 없애고, 최적화된 상태에서 일을 처리하게끔 합니다. 이 과정은 무효화-유효화 과정동안 일어나며, 그것에 라이프사이클의 핵심이라 할 수 있습니다.

 

그림과 같이 컴포넌트의 탄생과 죽음의 과정은 크게 7단계의 과정으로 설계되었고, 무효화-유효화 과정을 반복하게 됩니다.



























1. 생성(Construction)

 가장 처음단계로 어떤 컴포넌트를 생성할 때의 단계입니다. 우리가 버튼컴포넌트를 생성할 때 다음과 같이 선언합니다. 

 

var myButton:Button = new Button();

 

 

2. 추가(Addition or Attachment)

addChild()로 부모에 자식을 추가할 때의 단계입니다. 본격적인 컴포넌트 삶(lifecycle)이 시작된다고 볼 수 있습니다.

 

this.addChild(myButton);

 

UIComponent클래스의 addChild() 함수의 코드를 보면 아래의 3가지 서브함수로 나누어 놓았습니다. 이유는 addChild()가 호출되면 부모와 자식간에 많은 일들이 일어나게 되는데, 이유는 addChild()호출로 발생되는 일들을 좀 더 효율적으로 통제하기위함입니다.   각 sub함수

 

 addingChild()

 addChild()함수가 호출되면 가장 먼저 실행되는 함수입니다. 

 ① 부모와 자식객체 컴포넌트에 대한 참조문서를 셋팅 합니다. 

 ② LayoutManager을 정의합니다.

 ③ 어느 폰트가 이용가능한지를 정의합니다.

 ④ 컴포넌트 style에 대한 전파와 관리를 합니다.

 $addChild()

 addingChild()함수가 완료되자마자 호출됩니다.

 display list에 컴포넌트를 실질적으로 추가시키는 Flash Player레벨의 함수입니다. Flash Frame의 랜더링 단계동안 컴포넌트를 모니터에 그리는게 가능하도록 하는 것입니다.

 childAdded()

 자식컴포넌트가 초기화 되어있지 않다면, 자식의 initialize() 함수를 호출합니다. 그리고 초기화 단계를 시작합니다.

 

 

3. 초기화(Initialization)

초기화(Initialization)단계는 컴포넌트의 자식생성을 완료하는데 마무리를 짓는 단계입니다.  그리고 무효화(Invalidation)와 유효화(Validation)단계를 시작을 위한 준비단계입니다. 부모의 childAdded()함수가 initialize()함수를 호출함으로 초기화 단계를 시작합니다. 초기화 단계동안 아래의 2가지 Event가 송출되고 4가지 함수가 호출됩니다.

 

 1. FlexEvent.PREINITIALIZE 송출

 
 2. createChildren() 호출

   어떤 확장 컴포넌트를 생성하고 자식에 추가합니다.

 3. childrenCreated() 호출

 처음으로 무효화(Invalidate)와 유효화(Validate)사이클을 시작합니다.

 4. initializeAccessibility() 호출

   flash player 접근시스템(accessibility system)을 사용하기 위해 컴포넌트를 설정 합니다.
 5. initializationComplete() 호출    FlexEvent.INITIALIZED 이벤트를 호출하는 processedDescriptors setter메소드를 정의합니다.

 


*createChildren()함수

여기서 주의깊게 보아야 할 것이 createChildren()함수 입니다. createChildren()함수는 확장된 컴포넌트를 또 확장 가능하게 합니다. 다시말해 자식에 또 자식을 둘 수 있도록 하는것(복합 컴포넌트)이 createChildren()함수 입니다. 예를들면 halo계열 Button컴포넌트 소스를 보시면, createChildren()함수를 override하고있습니다.  그 함수 내부를 보면 Button컴포넌트의 자식으로 TextFiled가 생성되고 있고, TextFiled의 styleName속성도 정의되어 있습니다. 그리고 생성된 TextFiled객체를 Button에 addChild() 하고 있습니다. 이말은 내부적으로 TextFiled의 삶 또한 시작되었다는 말입니다. 이러한 자식이 추가되고 자식의 자식도 추가되고 하는, 전체적인 흐름을 읽고 이해하셔야 합니다.  그리고 createChildren()메소드에서는 무효화 메소드가 없습니다. 즉, 컴포넌트가 부모에게 추가된 후, 다시 호출되지 않고 딱 한번만 호출됩니다.

  


 

4. 무효화(Invalidation)

무효화(Invalidation)단계는 성장과 성숙의 단계입니다. Flex의 삶에 처음으로 반복되는 과정입니다. 초기화 단계(Initialization)에서 createChildren()메소드가 호출되어 자식이 생성된 후 childrenCreated()함수가 호출됩니다. childrenCreated()함수는 아래 3가지 함수를 호출합니다.

 

 invalidateProperties()

  컴포넌트 속성이 바뀔때 마다 호출됨. commitProperties()메소드 호출을 예약함.
 invalidateSize()   The invalidateSize method is called whenever some action i.e. changes in property or user action which requires the     components to re-calculate its size and its children’s size. measure()메소드 호출을 예약함.
 invalidateDisplayList()    The invalidateDisplayList method is called whenever some changes that requires component display list to be updated. updateDisplayList()메소드를 예약함.

 

 

5. 유효화(Validation)

Thus whenever invalidate method is called LayoutManager of Flex Application keeps track of which invalidate method is called and only calls corresponding validate method during validate phase.

The fourth method of validate phase is layoutChrome, this method is responsible for creating border or padding around children content.

 

Thus once validate cycle of component is executed LayoutManager will make component dispatch Event.UPDATE_COMPLETE event.

Note: The Invalidate - Validate cycle of component repeat itself as an when any changes are made to the component and component is not removed from its parent

 commitProperties()

 최종적으로 바뀐 properties 설정값들을 결정을 내림

 measure()

 UIComponent의 기본 크기와 최소 크기를 계산하는 로직을 추가

 layoutchrome()  그리기 작업1, 테두리 작업 
 updateDisplayList()

 comiitProperties()와 measure()에서의 속성,크기를 바탕으로 화면에 그림. 혹은자식을 배치하는 로직을 추가

* okgosu책 참조

 

 



* 무효화-유효화 메커니즘


 무효화과정을 설명하기 위해서는 유효화과정과의 쌍방 상호작용이 어떻게 일어나고, 정의되는지를 알아야 합니다. 무효화-유효화의 사이클이야말로 FlexLifeCycle의 핵심이라 할 수 있고, Flex의 강력함을 나타내줍니다.

 

myButton.width = 20;

myButton.width = 25;

 

위와같은 코드가 있다고 가정해봅시다.

 

첫번째 라인에서 width의 setter는 myButton의 사이즈를 업데이트하기위해 모든 계산을 바로바로 끝낼것입니다. 컴포넌트 자신의 width값을 정하고 실제 myButton의 레이아웃또한 update를 할 것입니다. 그리고 width값에 따라 자식과 부모의 레이아웃 배치 또한 계산되이 될 것입니다. 두번째 라인을 만나면 어떻게 될까요? 위의 모든 과정이 두번 일어나게 됩니다. 실행시간 또한 두배가 되겠죠. 그렇다면 위와같이 똑같은 설정이 두번 선언되어있을 때, 이를 감지하고 마지막 줄에 대한 width값만 set하면 낭비없이 width값을 설정할 수 있겠죠? 이러한 기능을 하는것이 무효화-유효화 과정입니다.

 

무효화-유효화 과정이 이러한 문제를 flag system을 활용해서 해결하고 있습니다. UIComponent의 width속성의 set을 보면 다음과 같습니다.  가장먼저 값이 바뀌었는지를 검사합니다. 값이 바뀌었을때만 invalidateSize()메소드를 호출합니다.

   


invalidateSize()메소드는 간단하지만, 매우 강력한 기능의 함수입니다. 먼저 invalidateSizeFlag변수를 두어 사전에 invalidateSize()함수가 호출되었는지를 검사합니다. 그리고 부모가 있는지 검사하고 LayoutManager객체에 등록을 합니다. 만약 invalidateSize()함수가 호출된 적이 있고, 유효화단계를 아직 거치지 않았다면 layoutManager등록에 대해 걱정할 필요는 없습니다. 왜냐하면 우리는 다음 유효화 단계에서 이미 유효화를 위한 사이즈를 이미 등록을 했기 때문입니다.  myButton에 대한 set width를 수천줄 적는다고 해서, 퍼포먼스가 떨어지거나 하지는 않습니다.

 

LayoutManager에 컴포넌트가 등록이 되면, 매우 기발한 코드가 실행됩니다. 다음단계의 Event.RENDER이벤트가 송출되자마자, 유효화 단계의 실행을 위해 callLater()함수가 실행됩니다. callLater()는 화면에 렌더링 되기 전에 실행가능한 마지막 코드입니다.

 

 

Now that our component is registered with the LayoutManager, some prettyingenious code is executed. What that LayoutManager does, is it uses the
callLater() method on a hidden UIComponent instance to execute the validation phase once the next Event.RENDER event is dispatched from the stage. If you recall
from Sean Christmann’s article, the RENDER event is dispatched to allow user code to be executed just before the Flash Player draws the display stack to screen. By
running the validation phase after the RENDER event guarantees us that this is the last possible code to be executed before the screen is rendered14.
The LayoutManager acts as a queuing system, tracking all the components that register invalidation changes before the next RENDER pass. When the LayoutManager
gets the RENDER event, it checks to see what components have registered with it during the invalidation phase and then begins executing the validation phase on
those objects. If the LayoutManager is in the process of executing validation on a set of components and new components register with the LayoutManager, these new
components will be queued for the next RENDER pass. This helps prevent an endless cycle of updates during a single pass.
The process of Invalidation and Validation is a cycle because any time a property changes it invalidates the component; the validation process must then be executed
again to put the component back into a valid state.

 

 

 

 

 

 

 

 

 

 

6. 업데이트(Update)

업데이트 단계는 컴포넌트가 무효과되고 유효화 사이클을 돌때마다 발생합니다. 컴포넌트가 LayoutManager를 유효화시키자마자, UPDATE_COMPLETE이벤트를 송출합니다. 이 과정은 부모로부터 해당 컴포넌트가 제거될때 까지 스스로 반복됩니다. 업데이트단계에서 컴포넌트가 라이브사이클의 어느 부분에서 시간을 소비하는지 알아야합니다.

 

 

7. 제거(Removal or  Detachment)

 

마지막단계인 제거단계입니다.  이 단계는 부모컴포넌트가 없으면 발생하는 단계입니다. 대부분의 경우 부모컴포넌트에서 removeChild()함수가 호출되면 발생하게 됩니다.

The last phase of a component life-cycle is removal phase. This phase is triggered when the component is no longer parented i.e., when removeChild() method is called on the parent component, passing in the component to remove as a reference.

When removeChild() method is called on parent component then three methods are fired, removingChild(), $removeChild() and childRemoved().

The removingChild() method does not perform any operation, this method can be overridden to execute tasks/operation that needs to be perform before component is removed from display stack

The $removeChild() method is actually a Flash Player level method that removes component from display stack.

The childRemoved() method removes references of component form its parents and document properties.

Once reference from component's parent is removed component can be re-parented or are available for garbage collection. Also removal of parent refrence of compoenent prevent component fromm entering the Invalidate-Validate cycle

 

 removingChild()  The first method called is removingChild() which by default (at the
UIComponent level) does nothing. This can be overridden to perform functionality
before the component is removed from the display stack.
 $removeChild()  The next method called is $removeChild() which is a Flash Player level method that
does the actual removal of the component from the display stack and then checks
the components references in memory. If there are no references to the component(such as other object pointing the component, event listeners with strong reference
set, etc.) the component is then marked for garbage collection.
 childRemoved()  Finally, the childRemoved() method is called removing references to the
components parent and document properties. This enables the component to be reparented
if required and also prevents the component from entering the
Invalidation‐Validation cycle.

 

 

 

 

예제를 통해 흐름을 눈으로 확인하면서 보겠습니다.  다음 예제의 구조는 다음과 같이 최상위Application안에 커스텀VGroup이 있고, 그 자식으로 커스텀Button이 있습니다. 각각의 단계에서 송출되는 이벤트와 발생되는 함수들을 trace로 찍고, 그 순서를 알아보기 쉽게 나타내 보았습니다.

 

 *souce code :ComponentLifecycleExample.fxp

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

이벤트가 발생했다는것은 말 그대로 생성완료(creationComplete) 되었다는 의미이고, 그 말은해당 컴포넌트가 화면에 그려졌다는 의미입니다. 그렇다면 최상위 부모인 Application의 creationComplete가 발생했다는것은, Application의 모든 컴포넌트(자식포함)들이 그려졌다는 것을 의미합니다.

 

위의 것들을 정리하면 다음과 같습니다.

1. creationComplete이벤트는 모든 컴포넌트들의 초기화(preinitialize, initialize)가 끝난 후 발생한다.

2. 컴포넌트들의 초기화 순서는 가장 자식컴포넌트부터 발생한다. ( 초기화 순서 : MyButton -> MyVGroup -> Application)

3. creationComplete이벤트 또한 가장 자식컴포넌트부터 발생한다. ( creationComplete이벤트 호출순서 : MyButton -> MyVGroup -> Application)

4. 최상위 부모인 Application의 creationComplete이벤트가 발생했다는 것은 모든 컴포넌트들의 초기화와 화면에 그려지는 작업이 끝났음을 의미한다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Q1) 무효화 메커니즘이란?

-> 플렉스 뿐만아니라 유저 인터페이스를 랜더링하는 프로그램에서 화면 업데이트 횟수를 최소하 하기 위한 알고리즘.

 

 

Q2) 컴포넌트의 속성이 바뀌었을 때 화면에 업데이트 하기 위해서는?

-> invalidateProperties() 함수를 호출 해 commitProerties()를 호출하게 함.

 

Q3)  컴포넌트의 속성이 바뀌거나 화면이 업데이트됨으로써 각 컴포넌트의 크기를 다시 계산하려면?

-> invalidateSize() 함수를 호출해 measure()가 실행되게 한다. measure() 함수에서는 컴포넌트 속성값의 변화에 따른 컴포넌트의 크기를 다시 계산한다.

 

 

 

 

 

 

 

 

2.무효화(無效化) 메커니즘(Invalidation Mechanism)

 

http://sibirjak.com/osflash/projects/as3commons-ui/invalidation-lifecycle/

http://flexdocs.kr/docs/flex2/docs/00001724.html

 

3. 강결합, 약결합

 

 

4. UIComponent LifeCycle

 

아래 그림은 제가 구글링해서 얻은 UIComponent의 생성과정을 가장 잘 나타내고 있는 그림입니다.

 

*출처 : http://danorlando.com/?p=122

 

 

 

 

 

 

 

 

 


AND

 

Googling으로 구한 소스를 진행중인 프로젝트에 Copy&Paste를 해서 개발하는 도중 제가 의도치 않은 곳에서 이벤트가 발생하는 경우가 있었습니다.  뜻하지 않은 현상으로 엄청난 삽질을 했습니다. 원인은 Flex에서는 이벤트 흐름이라는 것이 존재한다고 합니다. 지금까지는 그냥 addEventListener()만 붙이고 동작유무에 이상이 없었으니 이벤트 흐름따위한테는 관심이 없었더랫죠. 이벤트가 발생하는 background에서 어떤 특수한 흐름이 존재하리라고는 꿈에도 생각을 못했었습니다.  그리하여 미루고 미뤄왔던 이벤트 흐름을 제 나름대로(?) 심도있게(?) 공부한 글입니다. 아직 초보개발자의 글인 만큼 부족한 점이 많을 수 있으니, 잘못된 점이나 보완해야할 점 등 어떠한 feedback도 환영합니다.

 

Flex에서 이벤트가 송출(dispatch)될 경우, 어떤 특수한 단계의 이벤트 전파(propagation)가 일어납니다.  그 특수한 단계는 3단계로 이루어져 있었습니다.

 

Capture -> Target -> Bubble

 

각 단계에 대한 설명은 다음과 같습니다.  * okgosu의 플렉스4.5 플래시 빌더정석中

  캡쳐링capturing 단계

 이벤트가 발생하면 최상위 컴포넌트부터 이벤트가 발생한 바로 상위 컴포넌트까지 차례로 이벤트 리스너가 있냐 없냐를 체크하는 단계

  타겟팅targeting 단계

 캡쳐단계에서 발견한 이벤트 리스너를 호출하는 단계 

  버블링bubbling 단계

 타겟 단계에서 상위 컴포넌트로 이벤트 리스너들을 체크하는 단계

  

이해를 돕기위해 다음의 예제를 만들어보았습니다.

<?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"

                     width="700" height="252"

                     creationComplete="init()">

      <s:layout>

            <s:HorizontalLayout verticalAlign="middle" horizontalAlign="center"/>

      </s:layout>

     

      <fx:Script>

            <![CDATA[

                 

                  private function init():void

                  {

                        myBox1.removeEventListener(MouseEvent.CLICK, showPhase, !capturing.selected);

                        myBox2.removeEventListener(MouseEvent.CLICK, showPhase, !capturing.selected);

                        myBox3.removeEventListener(MouseEvent.CLICK, showPhase, !capturing.selected);

                        myBox4.removeEventListener(MouseEvent.CLICK, showPhase, !capturing.selected);

                       

                        myBox1.addEventListener(MouseEvent.CLICK, showPhase, capturing.selected);

                        myBox2.addEventListener(MouseEvent.CLICK, showPhase, capturing.selected);

                        myBox3.addEventListener(MouseEvent.CLICK, showPhase, capturing.selected);

                        myBox4.addEventListener(MouseEvent.CLICK, showPhase, capturing.selected);

                  }

                 

                  private function showPhase(event:MouseEvent):void

                  {

                        monitor.text += "event.target.name : " + event.target.name + ", "

                                          + "event.currentTarget.name : " +  event.currentTarget.name + ", "

                                          + "event.eventPhase : " + event.eventPhase

                                          + "\n";

                  }

            ]]>

      </fx:Script>

     

      <mx:VBox id="myBox4" width="200" height="200" backgroundColor="#FF0000" horizontalAlign="center" verticalAlign="middle" name="BOX4">

            <mx:VBox id="myBox3" width="150" height="150" backgroundColor="#00FF00" horizontalAlign="center" verticalAlign="middle" name="BOX3">

                  <mx:VBox id="myBox2" width="100" height="100" backgroundColor="#0000FF" horizontalAlign="center" verticalAlign="middle" name="BOX2">

                        <mx:VBox id="myBox1" width="50" height="50" backgroundColor="#FFFF00" name="BOX1">

                        </mx:VBox>

                  </mx:VBox>

            </mx:VBox>

      </mx:VBox>

     

      <s:VGroup>

            <s:TextArea id="monitor" width="450" height="200"/>

            <s:HGroup>

                  <s:CheckBox label="isCapture" id="capturing" change="init()"/>

                  <s:Button label="Clear" click="monitor.text=''" />

            </s:HGroup>

      </s:VGroup>

</s:Application>

*source :EventFlow.fxp

 

여러개의 VBox컴포넌트들을 위와같이 부모-자식으로 묶여져 있습니다. 각 색깔을 클릭해보면 이벤트의 흐름을 확인하실 수 있습니다.  useCapture의 Default값은 false이므로 초기 캡쳐링 단계는 생략됩니다.  target은 이벤트가 발생된 근원지를 나타내고 있으며, currentTarget은 현재 이벤트가 발생되고있는 지점을 나타내고 있습니다. phase는 이벤트 단계를 나타냅니다. ( phase1:Capturing, phase2:Targeting, phase3:Bubbling)     체크박스에 체크를 하면 Capturing단계에서만 리스닝하게 되고, 체크를 풀면 Targeting,Bubbling단계에서만 리스닝을 하게 됩니다. 세단계 모두에 리스너를 달고 싶으면 removeEventListener를 제거해주면 됩니다.

 

이벤트에 관한 문서의 내용을 요약하면 다음과 같습니다.

 

* Flex에서의 이벤트 특징

 

①  한번 리스너 이벤트가 성공적으로 등록되면, 추가적으로 등록되는 이벤트들과의 우선순위를 바꿀 수 없습니다. 우선순위를 바꿀 수 있는 유일한 방법은 removeListener()를 한 다음 다시 등록하는 방법밖에 없습니다.

 

②  useCapture 옵션을 다르게 등록하면 별도의 리스너가 등록됩니다. 예를들면 다음과 같은 코드가 있다고 가정한다면, '마징가'에는 두개의 리스너가 달리는 것입니다. 여기서  주의하실 점은 각각의 설정한 단계에서만 리스닝을 한다는 것입니다.

    

     마징가.addEventListener(MouseEvent.Click, test, true);         // Capture단계에서만 Listening 함.

     마징가.addEventListener(MouseEvent.Click, test, false);        // Target, Bubble단계에서만 Listening 함.

 

target단계에서만 리스너를 등록을 하고싶다거나, bubble단계에서만 리스너를 등록한다나 하는것은 불가능 합니다. 그 이유는 bubble단계는 오직 target노드의 조상에게만  버블링 할 수 있도록 되어있기 때문입니다.

 

송출된 객체가 존재하면(useWeakReference가 true가 아니라면) 가비지 콜렉터는 메모리에서 자동적으로 리스너를 제거하지 않기 때문에, 리스너가 필요하지 않게 되면 필히  removeEventListener() 하십시오.                                                                                                *이미지 출처 : ActionScript 도움말

 

⑤ EventDispatcher 인스턴스를 복사한다고 해서 리스너까지 복사되는 것은 아닙니다. 하지만 EventDispatcher 인스턴스를 옮기는 경우에는 리스너까지 따라갑니다.

 

⑥ If the event listener is being registered on a node while an event is being processed on this node, the event listener is not triggered during the current phase but can be triggered during a later phase in the event flow, such as the bubbling phase. 

 

⑦  If an event listener is removed from a node while an event is being processed on the node, it is still triggered by the current actions. After it is removed, the event listener is never invoked again (unless registered again for future processing).

 

 

 

* addEventListener() 메소드 파라미터

 

flash.display.Stage.addEventListener(type:String

     , listener:Function

     , useCapture:Boolean=false

     , priority:int=0

     , useWeakReference:Boolean=false):void 

 

 

 type 

 

 - 이벤트 타입

 

 userCapture

 

 - 리스너를 (Capture단계) or (Target, Bubble단계) 어디에 붙일 지를 정함

 - true 설정하면 Capturing .

 - false 하면 Targeting Bubbling .

 - Capture,Target,Bubble 단계 모두 리스닝 하려면위의 '마징가' 같이 addEventListener 두번 붙여줘야함.

 

 priority

 - 리스너의 레벨 우선순위 정함.

 - 32비트 integer 지정함.

 - 높은 수일수록 우선권이 높음.

 - 우선순위가 똑같으면 추가된 순서되로 진행됨.

 - 디폴트값은 0

 useWeakReference

 

 - 강참조(strong reference), 약참조(weak reference) 정함

 - 디폴트는 강참조.

 - 강참조는 가비지콜렉트 하는것을 막음. 약참조는 가비지콜렉트 하도록 내버려둠.

 - 클래스레벨 멤버 함수는 가비지콜렉션의 대상이 아님.    

   Class-level member functions are not subject to garbage collection, so you can set useWeakReference to true for class-level member functions without subjecting them to garbage collection. If you set useWeakReference to true for a listener that is a nested inner function, the function will be garbage-collected and no longer persistent. If you create references to the inner function (save it in another variable) then it is not garbage-collected and stays persistent.        

 

 

*도움이 되는 글

퍼플린님의 블로그 (Flex 이벤트의 전파단계와 버블링) http://rinn.kr/25

지돌스타님의 블로그(라이프사이클) http://blog.jidolstar.com/226

지돌스타님의 블로그(이벤트전파) http://blog.jidolstar.com/415

커스텀이벤트시 알아야할 사항 http://gogothing.tistory.com/51

지클짱께님의 블로그(Custom Event를 만들 때 clone() 함수를 override 해야하는 이유)  http://blog.naver.com/sinavari?Redirect=Log&logNo=40062521053

쫌조님의 블로그(Flex의 Single Thead와 비동기 프로그래밍 모델) http://blog.naver.com/PostView.nhn?blogId=jjoommnn&logNo=130050249083

AS3 Event http://bixworld.egloos.com/2149717

ActionScript 도움말 http://help.adobe.com/ko_KR/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7e4f.html

AND

PROTECTED ARTICLE. TYPE THE PASSWORD.

 

이 포스팅은 Sprite클래스와 Shape클래스가 무엇이며, 둘의 차이점이 무엇인지를 설명하고 있습니다.

 

먼저 Flash Player에서 표시객체(DisplayObject)의 하위클래스 구조를 보시면 다음과 같습니다.

 

 

                                                               *출처 : Adobe LiveDocs

 

 

보시다시피 Sprite클래스와 Shape클래스 둘다 화면에 보여지는 표시객체(DisplayerObject)의 자식들 입니다. 즉 두 클래스 모두 도형을 그리는 작업이 가능합니다. 차이점이 있다면 Sprite클래스는 InteractiveObject를 자식이기 때문에 Shape클래스와는 달리 Sprite클래스로 그린 도형에는 어떠한 액션을 줄 수 있습니다. 예를들면 Sprite로 그린 도형은 드래그가 가능하게 할 수 있고, 마우스 클릭 이벤트를 줄 수도 있습니다. Shape클래스로 만든 도형은 불가능 하죠. Shape클래스는 단지 보여지는 도형만 만들 뿐입니다. 하지만 Shape클래스는 Sprite클래스보다 퍼포먼스가 훨씬 뛰어나다고 합니다. 액션을 줄 수 없는 대신, Sprite클래스보다 훨씬 가볍다는 말이죠.

 

정리하면 다음과 같습니다.

 

 Sprite클래스

Shape클래스 

 

 DisplayObject의 자식(그래픽 요소를 보여줄 수 있음)

 

표시객체 컨터이너 O (자식표시객체를 포함 할 수 있음)

표시객체 컨테이너 X (자식표시객체를 포함 할 수 없음)

상대적 메모리 사용률↑

상대적 메모리 사용률↓

이벤트 줄 수 있음 (Interaction 속성과 메소드 있음)

이벤트 줄 수 없음 (Interaction 속성과 메소드 없음)

 

 

Sprite클래스의 주요 속성과 메소드를 정리 하면 다음과 같습니다.

 

 *출처 :  okgosu의 액션스크립트 정석

주요 속성과 메소드 

 설명 

속성 

 buttonMode : Boolean

 스프라이트 객체를 버튼 모드로 설정함

 (마우스를 올리면 손 모양 커서로 바뀜) 

 dropTarget : DisplayObject

 드래그되거나 드롭되는 디스플레이 오브젝트

 graphics : Graphics

 스프라이트에서 드로잉을 위한 그래픽 객체 

 hitArea : Sprite

 히트 영역은 사용자 인터랙션을 일으킬 영역으로 별도로 지정하지 않으면 그 Sprite가 그리는 영역이 된다. 

 soundTransform : SoundTransform 

 스프라이트의 사운드를 컨트롤 

 useHandCursor : Boolean

 마우스를 올렸을 때 핸드 커서가 나타나게 할지 여부로, buttonMode가 true일 때 작동함 

 메소드

 startDrag(lockCenter:Boolean=false, bounds:Rectangle = null):void

 스프라이트를 드래그할 수 있게 함 

 stopDrag():void 

 startDrag()메소드 작동을 멈춤 

 

 

 

<?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"

                     creationComplete="init();">

      <fx:Script>

            <![CDATA[

                  import mx.core.UIComponent;

                  private function init():void

                  {

                        var shapeCircle:Shape = new Shape();

                        shapeCircle.graphics.beginFill(0xFF0000, 1);

                        shapeCircle.graphics.drawCircle(100, 100, 100);

                       

                        var spriteCircle:Sprite = new Sprite();

                        spriteCircle.graphics.beginFill(0x00FF00, 1);

                        spriteCircle.graphics.drawCircle(100, 100, 100);

                        spriteCircle.x = 100;

                       

                        var container:UIComponent = new UIComponent();

                       

                        container.addChild(shapeCircle);

                        container.addChild(spriteCircle);

                       

                        addElement(container);

                  }

            ]]>

      </fx:Script>

</s:Application>

*source code:ShapeExample1.fxp

 

위 예제는 Shape클래스를 이용해 원을 하나 그리고, Sprite클래스를 이용해서 또다른 원을 그리는 예제입니다. 

다음은 Shape형 객체 shapeCircle의 속성과 Sprite형 객체 spriteCircle의 속성을 나타냅니다. spriteCircle에서는 shapeCircle에는 없는 InteractiveObject의 속성들을 사용할 수 있습니다.

 

 

AND

 

 

 

-Flash Player에서 관리하는 표시객체의 계층구조-

 

* 여기저기서 swf을 로드하더라도 Stage은 단 하나이고, 각 swf들은 각기 하나의 root를 가진다. 

 

 

 

-표시객체의 하위클래스 구조-

*source : http://livedocs.adobe.com/flash/9.0_kr/ActionScriptLangRefV3/

AND

 

배열이라는 것은 비슷한 Data를 저장해 놓은 것인데, 저장하는 방법이 두 가지가 있습니다. 첫번째로 0부터 순서대로 번호를 매겨서 그 번호로 원소를 찾는 방법(인덱스 배열, indexed array)이 있고, 두번째로 번호 대신에 문자열이나 객체등으로 배열의 원소를 찾는 방법(연관 배열, associative array)이 있습니다.

 

 이 포스팅은 Actionscript에서 연관배열을 만드는 클래스인 Dictionary에 대해 간단히 알아보겠습니다.

 

1. 연관배열

 

Dictionary클래스를 알아보기전에 연관배열(Hash 혹은 Map이라 부름)이 무엇인지 알아보고, actionscript에서 연관배열을 어떻게 만드는지 알아보겠습니다.

 

위에서 언급했듯이 연관배열이란 Key에 Data를 짝을 지어주어 자료를 저장하고, 그 Key값으로 해당 Data를 찾는 것입니다.

 

연관 배열(associative array)은 자료구조의 하나로, 여러 개의 (키, 값)을 담으며 키를 통해 그에 연관되는 값을 접근할 수 있다. 연상 배열, 결합형 배열, (map), 사전(dictioanry)으로 부르기도 한다.

* 출처 : 위키피아

 

Actionscript에서 연관배열을 만드는 방법에는 두가지가 있습니다.  아래는 연관배열을 만드는 두가지 방법을 나타내주는 간단한 예제입니다.

 

 

<?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"

                     creationComplete="init();">

      <fx:Script>

            <![CDATA[

                 

                  // 1-1. 객체 리터럴을 사용하여 선언과 동시에 초기화

                  private var capitalInfo:Object = {national : "KOREA", capital : "SEOUL"}; 

                  private var capitalInfo2:Object;

                  private var capitalInfo3:Array;

                 

                  private function init():void

                  {

                        // 1-2. Object클래스의 생성자를 이용하여 초기화

                        // 키값에 공백이 있으면 안됨

                        capitalInfo2 = new Object();

                        capitalInfo2["national"] = "KOREA";

                        capitalInfo2["capital"] = "SEOUL";

                       

                        // 2. Array유형으로 선언할 경우 객체 리터럴을 사용할 없다.

                        //    array속성 사용못함.별다른 이점 없음. 인덱스 배열만드는데 사용.

                        capitalInfo3 = new Array();

                        capitalInfo3["national"] = "KOREA";

                        capitalInfo3["capital"] = "SEOUL";

                  }

                 

                  private function show():void

                  {

                        window.text += capitalInfo["national"] + "-";

                        window.text += capitalInfo["capital"] + "\n";

                        window.text += capitalInfo2["national"] + "-";

                        window.text += capitalInfo2["capital"] + "\n";

                        window.text += capitalInfo3["national"] + "-";

                        window.text += capitalInfo3["capital"] + "\n";

                  }

            ]]>

      </fx:Script>

      <s:VGroup>

            <s:TextArea id="window" />

            <s:Button label="SHOW" click="show();"/>

      </s:VGroup>

</s:Application>

*source code :ObjectExample1.fxp

 

연관배열을 만드는 첫번째 방법은 Object클래스를 이용하는 것이고, 두번째 방법은 Array클래스를 이용하는 방법이 있습니다.

 

위의 예제에서 세가지 객체 capitalInfo, capitalInfo2, capitalInfo3들은 똑같은 Data를 가지고 있는 객체들입니다. 각기 다른방법으로 생성되어있습니다.

첫번째 객체 capitalInfo은 선언과 동시에 초기화 되어있습니다. 참고로 이와같이 선언과 동시에 초기화 하는 것은 객체리터럴이라 합니다.

두번째 객체 capitalInfo2은 Object클래스의 생성자를 이용하여 초기화 합니다. 주의하실점은 키값에 공백이 있어서는 안됩니다.

세번째 객체 capitalInfo는 Array클래스를 이용합니다. Array클래스를 이용할 경우 첫번째 객체처럼 객체리터럴을 사용할 수 없으며, Array클래스가 가지는 이점들, 속성등을 이용할 수는 없습니다. 특별히 좋은 점은 없다는 결론입니다.

* 연관배열을 만들 경우 Array를 사용하여 만들지 마시고, Object를 이용하세요. Array는 태생이 인덱스배열이기 때문에 권장하는 방법이 아닙니다. 자세한 내용은 검쉰님의 블로그에 잘 나와있습니다.

 

 

 

2. Dictionary클래스

 

지금까지 내용을 요약하면, "연관배열을 만드는 방법에는 Object클래스를 이용하는 방법과, Array클래스를 이용하는 방법이 있는데 Array클래스 보다 Object클래스를 이용하는 것을 권장한다." 입니다.

Object클래스로 연관배열은 만들경우 KEY값으로 문자열이 들어가는데, KEY값으로 문자열 뿐만 아니라 객체를 KEY값으로 할 수 있습니다. 그것이 바로 Dictionary클래스 입니다.

 

Dictionary 클래스는 객체유형을 키로 사용하여 요소를 구분할 수 있는 연관배열입니다.

 

 

Dictionay클래스는 Actionscript 3.0에 도입된 연관배열입니다.  특이한 점이 있다면 Dictionary클래스는 문자열이 아니라 객체를 키값으로 갖는다는 것입니다.

 

자세한 내용은 Reference를 보시면 자세히 나와있습니다.

 

내용의 핵심은 다음과 같습니다.

- Dictionary는 순서나 정렬이 되지 않은 정렬되지 않는 키/값 쌍 모음이다.

- Dictionary에 쓰이는 키 값으로 꼭 String타입이 아니더라도 됩다. 일반적으로 Object클래스의 인스턴스가 사용.

 

 

 

 

 

 

 

 

 다음은 Reference에 나와있는 간단한 예제입니다.

<?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"

                     creationComplete="init();">

      <fx:Script>

            <![CDATA[

                 

                  private function init():void

                  {

                        var groupMap:Dictionary = new Dictionary();

                       

                        // 키로 사용할 객체

                        var spr1:Sprite = new Sprite();

                        var spr2:Sprite = new Sprite();

                        var spr3:Sprite = new Sprite();

                       

                        // 값으로 사용할 객체

                        var groupA:Object = new Object();

                        var groupB:Object = new Object();

                       

                        // 사전에 - 쌍을 만듭니다.

                        groupMap[spr1] = groupA;

                        groupMap[spr2] = groupB;

                        groupMap[spr3] = groupB;

                       

                        if(groupMap[spr1] == groupA)

                        {

                             trace("sprl1 is in groupA");

                        }

                        if(groupMap[spr2] == groupB)

                        {

                             trace("sprl2 is in groupB");

                        }

                        if(groupMap[spr3] == groupB)

                        {

                             trace("sprl3 is in groupB");

                        }

                  }

            ]]>

      </fx:Script>

</s:Application>

*source code :DictionaryExample.fxp

 

 

< 결과 > 

 

 

 

if문을 통해  Key에 저장되어 있는 Data를 확인할 수 있습니다. 그렇다면 사전에 저장되어있는 모든 Key와 Data를 출력해보겠습니다.

 

for ..in 루프를 통해 출력해보면 다음과 같습니다.

 

 

 for(var key:Object in groupMap)

 {

     trace(key, groupMap[key]);

 }

 

 

< 결과 >

 

Dictionary 객체의 값에 직접 액세스 하려면 for each ..in 루프를 사용합니다.

 

 

 for each(var item:Object in groupMap)

 {

     trace(item);

 } 

 

 

< 결과 >

 

 

 

 

 

 

 

3. 객체 키 및 메모리 관리

 

* 다음 내용은 Adobe Dictionary Reference 내용을 그대로 옮겨놓은 것입니다.

 

Adobe® Flash® Player 및 Adobe® AIR™에서는 가비지 컬렉션 시스템을 사용하여 더 이상 사용되지 않는 메모리를 복구합니다. 객체에 객체를 가리키는 참조가 없을 경우 객체는 가비지 컬렉션의 대상이 되며 다음 번 가비지 컬렉션 시스템 실행 시 메모리가 복구됩니다. 예를 들어 다음 코드는 새 객체를 만들어 변수 myObject에 객체에 대한 참조를 할당합니다.

 

var myObject:Object = new Object();

 

객체에 대한 참조가 남아 있는 한, 가비지 컬렉션 시스템에서는 객체가 사용하고 있는 메모리를 복구하지 않습니다. 다른 객체를 가리키거나 null 값으로 설정되는 등 myObject 값이 변경되면, 원래 객체에 의해 사용되던 메모리는 가비지 컬렉션의 대상이 됩니다. 그러나 원래 객체에 대한 다른 참조가 없는 경우에만 해당됩니다.

Dictionary 객체에서 myObject를 키로 사용하는 경우 원래 객체에 대한 다른 참조가 만들어집니다. 예를 들어 다음 코드에서는 객체에 대한 두 개의 참조 즉, myObject 변수 및 myMap 객체의 키를 만듭니다.

 

import flash.utils.Dictionary;

var myObject:Object = new Object();
var myMap:Dictionary = new Dictionary();
myMap[myObject] = "foo";

 

myObject로 참조되는 객체를 가비지 컬렉션 대상으로 만들려면 객체에 대한 참조를 모두 제거해야 합니다. 이 경우, 다음 코드와 같이 myObject 값을 변경하고 myMap에서 myObject 키를 삭제해야 합니다.

 

myObject = null;
delete myMap[myObject];

 

또는 Dictionary 생성자의 useWeakReference 매개 변수를 사용하여 사전 키를 모두 약한 참조로 만들 수 있습니다. 가비지 컬렉션 시스템에서는 약한 참조를 무시하므로 약한 참조만 있는 객체는 가비지 컬렉션의 대상이 됩니다. 예를 들어 다음 코드에서는 객체를 가비지 컬렉션 대상으로 만들기 위해 myMap에서 myObject 키를 삭제할 필요가 없습니다.

 

 import flash.utils.Dictionary;

var myObject:Object = new Object();
var myMap:Dictionary = new Dictionary(true);
myMap[myObject] = "foo";
myObject = null; // Make object eligible for garbage collection.

 

 

* 참고

- Dictionary API

- Associative Array API

- Dictionary Reference

- 해피나님의 블로그 - Flex(Actionscript) 에서 Object 와 Dictionary 에 대한 고찰

- 검쉰님의 블로그 - Array를 왜 Hash로 쓰나요? Object 놔두고.

- AS3 Dictionary Class vs. Array vs. Object!

AND

 

이번 포스팅은 Flex의 ClassFactory가 무엇이며, 활용방법에 대한 글입니다. Flex Reference를 내 맘대로 해석한 것입니다.

 

ClassFactory 객체는 Flex에서 다른 클래스의 동일한 속성의 객체를 만들기 위해 사용하는 "factory object" 입니다. factory oject를 생성할 때, generator 클래스를 정의합니다. 그리고 properties속성들을 factory 객체에서 정의합니다. Flex는 factory 객체의 newInstance()메소드를 호출함으로 객체생성을 합니다. newInstance() 메소드는 generator 클래스의 새로운 객체를 만듭니다. 그리고 properties를 사용해 새로운 객체의 속성들을 정의합니다.  생성된 객체를 좀 더 커스터마이징 하고싶으면 newInstance()메소드를 오버라이딩 하시면 됩니다.

 

ClassFactory는 IFactory 인터페이스에 의해 구현됩니다. 그러므로 IFactory 타입의 속성으로 할당되는 객체를 생성할 수 있습니다. 가령 List컨트롤의 itemRenderer속성이나, DataGrid컨트롤의 itemEditor속성들이 있습니다.

 

예를들어보면 true/false가 될 수 있는 showProductImage속성을 포함하는 ProductRender라는 itemRenderer클래스를 만들 수 있습니다. 이러한 renderer를 사용하는 List컨트롤의 코드는 다음과 같습니다.

 

  var productRenderer:ClassFactory = new ClassFactory(ProductRenderer);
  productRenderer.properties = { showProductImage: true };
  myList.itemRenderer = productRenderer;
 

List컨트롤은 ProductRenderer의 개별적인 객체를 만들기 위해 itemRenderer의 newInstance() 메소드를 호출합니다. showProductImage속성은 true로 정의되 있습니다. 만약 product 이미지를 생략위한 다른 List컨트롤을 만들고 싶다면, properties속성을 이용해 { showProductImage: false } 이렇게 정의함으로 또다른 ClassFactory를 생성하기 위한  ProductRenderer 클래스를 사용하면 됩니다.

 

 

객체설정을 위해 properties속성을 사용할 수 있다는 것은 매우 유용하나,  properties속성을 일일이 정의할 필요가 없이 non-configurable 생성자 클래스를 생성하는것이 일반적입니다.  다음과 같이 테그안에 정의합니다.

  <mx:List id="myList" itemRenderer="ProductRenderer">

MXML컴파일러는 자동적으로 ClassFactory객체를 생성합니다.

 

요지는 테그안에 itemRenderer를 호출하면 컴파일러가 자동으로 ClassFactory를 생성해 주므로 따로 작업할 것이 없지만, 스크립트상에서는 ClassFactory를 이용해야합니다.  왜냐하면itemRenderer는 IFactory타입이고, ClassFactory클래스는 오만 타입(?)을 IFactory 타입을 반환해주므로!

 

* source - Flex Reference

* 참고 - 타울님의 블로그(Actionscript에서 ItemRenderer 사용하기)

AND

 

push()

 배열의 끝에 원소를 추가

 unshift()

 배열의 처음에 원소를 추가

 shift()

 배열의 첫 번째 원소를 제거

 pop()

 배열 맨 끝의 원소를 하나 지울 때

 splice()

 특정 인넥스의 배열을 지울 때

 split()

 문자열을 배열로 전환할 때

  join()

 배열을 문자열로 전환할 때

concat()

 배열을 복사할 때

  sort()

 오름차순 정렬

   Array.CASEINSENSITIVE : 대소문자를 구분하지 않고 정렬함

   Array.DESCENDING : 내림차순으로 정렬함

   Array.NUMERIC : 숫자값일 경우에 지정함

   Array.RETURNINDEXEDARRAY : 실제 배열은 정렬하지 않고 정렬된 인덱스만 리턴함.

   Array.UNIQUESORT : 배열의 각 원소값이 전부 다를 경우(유니크)에만 정렬하고 그렇지 않으면 sort() 결과로 배열 대신 0을 리턴함

 reverse()

 배열을 거꾸로 뒤집음

*source : okgosu의 액션스크립트 정석 中

 

AND

 

ArrayList와 ArrayCollection 모두 List Data를 저장, 관리 할 수 있습니다.  또한 둘 다 Flex에서 자동적으로 데이터바인딩 됩니다.

 

가장 큰 차이점은 ArrayCollection은 추가적으로 정렬과 필터 기능을 가지고 있습니다.

 

ArrayList는 Flex4버전에서 추가되었으며, ArrayCollection에 비해 좀 더 가볍다고 볼 수 있습니다.

 

* source : http://sunnytambi.blogspot.kr/2010/03/flex-4-arraylist-vs-arraycollection.html

 

 

다음 예제는 ArrayCollection의 필터링 기능을 활용한 예제 입니다.

 

 

<?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"

                     initialize="init()">

 

      <fx:Script>

            <![CDATA[

                  import mx.collections.ArrayCollection;

                 

                  [Bindable]

                  private var myArrayCollection:ArrayCollection;

                 

                  private var firstTime:Boolean = true;

                 

                  private function init():void {

                        myArrayCollection = new ArrayCollection;

                        var obj:Object = new Object;

                       

                        obj.teamName = "롯데";

                        obj.playerName = "강민호";

                        myArrayCollection.addItem(obj);

                        obj = new Object;

                        obj.teamName = "한화";

                        obj.playerName = "류현진";

                        myArrayCollection.addItem(obj);

                        //etc

                  }

                 

                  private function filter():void {

                        myArrayCollection.filterFunction = filterMyArrayCollection;

                        myArrayCollection.refresh();

                  }

                 

                  private function filterMyArrayCollection(item:Object):Boolean {

                        var searchString:String = myTextInput.text.toLowerCase();

                        var itemName:String = (item.teamName as String).toLowerCase();

                        return itemName.indexOf(searchString) > -1;

                  }

                 

                  private function clearMyTextInput():void {

                       

                        if (firstTime == true )

                        {

                             myTextInput.text = "";

                             firstTime = false;

                        }

                  }

                 

            ]]>

      </fx:Script>

     

      <mx:VBox right="10" left="10" bottom="10" top="10">

            <s:TextInput id="myTextInput" change="filter()"

                              enabled="true"

                              focusIn="clearMyTextInput()"

                              text="Filter/Search.."

                              width="100" height="26"/>

           

            <mx:DataGrid id="dataGrid"

                              dataProvider="{myArrayCollection}"

                              verticalScrollPolicy="on" dropShadowVisible="false" verticalAlign="top" editable="false" width="200" height="200" paddingTop="2">

                  <mx:columns>

                        <mx:DataGridColumn dataField="teamName"  headerText=""/>

                        <mx:DataGridColumn dataField="playerName"  headerText="선수이름"/>

                  </mx:columns>

            </mx:DataGrid>

      </mx:VBox>

     

</s:Application> 

*source : http://www.flex-blog.com/arraycollection-filter-example/

*source code :ArrayCollectionExample.fxp

 

 

* 참고 : Jeremy Mitchell님의 글 - ArrayCollection 문법
AND

 

 

다음은 ArrayCollection의 속성값으로 인덱스를 구하는 예제입니다. getItemIndex() 메소드는 객체 자체를 참조하기 때문에, 속성값으로 Index를 구할 수 없습니다.

 

 

 

<?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">

      <fx:Script>

            <![CDATA[

                  import mx.collections.ArrayCollection;

                  import mx.controls.Alert;

                  import mx.events.FlexEvent;

                 

                  [Bindable]public var dataList:ArrayCollection = new ArrayCollection([{name:"Kevin"}, {name:"Tom"}]);

                 

                  public function getItemIndexByProperty(array:ArrayCollection, property:String, value:String):Number

                  {

                        for (var i:Number = 0; i < array.length; i++)

                        {

                             var obj:Object = Object(array[i])

                             if (obj[property] == value)

                                   return i;

                        }

                        return -1;

                  }

                 

                  protected function creationCompleteHandler():void

                  {

                        var selectedIndex:int = getItemIndexByProperty(dataList, "name", myList.selectedItem.name);

                        Alert.show(selectedIndex.toString() + " : " + dataList.getItemAt(selectedIndex).name);

                  }

            ]]>

      </fx:Script>

      <s:List dataProvider="{dataList}" itemRenderer="IR" click="creationCompleteHandler();" id="myList"/>

</s:Application>

*source : http://stackoverflow.com/questions/8585300/flex-arraycollection-getitemindex-always-return-1

*source code :getItemIndexExample.fxp

AND

대역폭과 처리 리소스를 보존하기 위해 Flash Player는 아미크가 사운드를 전송하지 않는 때를 감지하려고 합니다. 마이크의 활동 레벨이 일정 시간 동안 묵음 레벨 임계값 미만을 유지하면 Flash Player는 오디오 입력 전송을 중지하고 대신 단순 ActivityEvent를 전달합니다. Speex코덱을 사용할 경우(Flash Player 10 이상 및 Adobe AIR 1.5 이상에서 지원)묵음 레벨을 0으로 설정해야 응용 프로그램에서 오디오 데이터가 연속적으로 전송됩니다. Speex 음성 활동 검출은 대역폭을 자동으로 줄입니다.

Microphone 클래스의 다음 세 가지 속성은 활동을 모니터링하고 제어합니다.

To conserve bandwidth and processing resources, Flash Player tries to detect when no sound is being transmitted by a microphone. When the microphone’s activity level stays below the silence level threshold for a period of time, Flash Player stops transmitting the audio input and dispatches a simple ActivityEvent instead.
Three properties of the Microphone class monitor and control the detection of activity:

 

 

● 읽기 전용 activityLevel 속성은 마이크가 감지하는 사운드의 양을 0~100의 등급으로 나타냄니다.

    The read-only activityLevel property indicates the amount of sound the microphone is detecting, on a scale from 0 to 100.

● silenceLevel속성은 마이크 활성화에 필요한 사운드의 양을 지정하고 ActivityEvent.ACTIVITY 이벤트를 전달합니다. silenceLevel 속성도 0~100의 등급을 사용하고 기본값은

    10입니다.

    The silenceLevel property specifies the amount of sound needed to activate the microphone and dispatch an ActivityEvent.ACTIVITY event. The silenceLevel property also uses a scale from 0 to 100, and the default value is 10.

● silenceTimeout 속성은 마이크가 현재 사용 중이지 않음을 알리기 위해 ActivityEvent.ACTIVITY 이벤트가 전달될 때까지 활동 레벨이 묵음 수준 미만을 유지해야 하는 시간을 밀리초

    단위로 정의합니다. 기본 silenceTimeout 값은 2000입니다.

    The silenceTimeout property describes the number of milliseconds that the activity level must stay below the silence level, until an ActivityEvent.ACTIVITY event is dispatched  to indicate that the microphone is now silent. The default silenceTimeout value is 2000.

 

Microphone.silenceLevel 속성과 Microphone.silenceTimeout 속성은 읽기 전용이지만 Microphone.setSilenceLevel() 메서드를 사용하여 이 값을 변경할 수 있습니다.

Both the Microphone.silenceLevel property and the Microphone.silenceTimeout property are read only, but their values can be changed by using theMicrophone.setSilenceLevel() method.


 

새로운 활동이 감지되었을 때 마이크를 활성화하는 프로세스에서 약간의 지연이 발생하는 경우도 있습니다. 마이크를 항상 활성화시켜 두면 이러한 활성화 지연을 방지할 수 있습니다. 응용 프로그램이 silenceLevel 매개 변수를 0으로 설정하여 Microphone.setSilenceLevel()메서드를 호출하면 Flash Player는 사운드가 감지되지 않더라도 마이크의 활성 상태를 유지하고 오디오 데이터를 계속 수집합니다. 반대로, silenceLevel 매개 변수를 100으로 설정하면 마이크가 전혀 활성화되지 않습니다.

In some cases, the process of activating the microphone when new activity is detected can cause a short delay. Keeping the microphone active at all times can remove such activation delays. Your application can call the Microphone.setSilenceLevel() method with the silenceLevel parameter set to zero to tell Flash Player to keep the microphone active and keep gathering audio data, even when no sound is being detected. Conversely, setting the silenceLevel parameter to 100 prevents the microphone from being activated at all.


다음 예제는 마이크에 대한 정보를 표시하고 Microphone 객체가 전달한 activity 이벤트 및 status 이벤트를 보고합니다.

The following example displays information about the microphone and reports on activity events and status events dispatched by a Microphone object. 

import flash,events.ActivityEvent;
import flash,events.StatusEvent;
import flash.media.Microphone;
var deviceArray:Array = Microphone.names;
trace("Available sound input devices:");
for (var i:int = 0; i < deviceArray.length; i++)
{
trace(" " + deviceArray[i]);
}
var mic:Microphone = Microphone.getMicrophone();
mic.gain = 60;
mic.rate = 11;
mic.setUseEchoSuppression(true);
Capturing sound input 621
mic.setLoopBack(true);
mic.setSilenceLevel(5, 1000);
mic.addEventListener(ActivityEvent.ACTIVITY, this.onMicActivity);
mic.addEventListener(StatusEvent.STATUS, this.onMicStatus);
var micDetails:String = "Sound input device name: " + mic.name + '\n';
micDetails += "Gain: " + mic.gain + '\n';
micDetails += "Rate: " + mic.rate + " kHz" + '\n';
micDetails += "Muted: " + mic.muted + '\n';
micDetails += "Silence level: " + mic.silenceLevel + '\n';
micDetails += "Silence timeout: " + mic.silenceTimeout + '\n';
micDetails += "Echo suppression: " + mic.useEchoSuppression + '\n';
trace(micDetails);
function onMicActivity(event:ActivityEvent):void
{
trace("activating=" + event.activating + ", activityLevel=" +
mic.activityLevel);
}
function onMicStatus(event:StatusEvent):void
{
trace("status: level=" + event.level + ", code=" + event.code);
}

*source : Actionscript 3.0 Reference

 

 

아래 예제는 Flex에서 마이크 활동을 감지하는 기본 예제입니다. 이를 활용해 Mic 이퀄라이저를 만들 수 있습니다.

 

 

 

<?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"

                     creationComplete="init();"

                     >

     

      <fx:Script>

            <![CDATA[

                  import flash.events.ActivityEvent;

                  import flash.events.StatusEvent;

                  import flash.media.Microphone;

                 

                  private var mic:Microphone;

                  private var sv:Number = 100;

                  private var sh:Number = 100;

                 

                  private function init():void

                  {

                        mic = Microphone.getMicrophone();

//                      Security.showSettings(SecurityPanel.MICROPHONE);

                        mic.setLoopBack(true);

                        mic.setUseEchoSuppression(false);

 

                        addEventListener(Event.ENTER_FRAME, stage_EnterFrame);

                  }

                 

                  private function stage_EnterFrame(e:Event):void

                  {

                        var num:Number = mic.activityLevel*4;

                        trace(num);

                        eq.graphics.clear();

                        eq.graphics.beginFill(0xffffff * Math.random());

                        eq.graphics.drawCircle(sv, sh, num);

                  }

            ]]>

      </fx:Script>

      <mx:UIComponent id="eq" />

</s:Application>

*source : http://www.youtube.com/watch?v=IYmdkvLVRgc

*source code :MicExample.fxp

 

핵심은 Microphone 클래스의 activityLevel속성과 ENTER_FRAME 이벤트입니다. 전체적인 흐름은 간단합니다. activityLevel 속성으로 마이크 활동량을 감지해 ENTER_FRAME이벤트로 반복적으로 activityLevel을 시각화 합니다. activityLevel의 값은 0~100으로 소리를 숫자로 표현합니다.

 

- ActionScript에서 Sound작업

* [ActionScript] 액션스크립트 사운드 프로그래밍

* [ActionScript] 옥고수님의 블로그(액션스크립트 3.0을 이용한 사운드 시각화)

* [ActionScript, Flash] Classic ‘Sound Equalizer’ in Flash/AS3

* [ActionScript] ActionScript Reference(Detecting microphone activity)

* [ActionScript] 사운드 아키텍처의 이해(Adobe Reference)

* [ActionScript, Flash] Simple ActionScript 3 Flash Microphone Visualizer

* [ActionScript] 동강님의 블로그 - Microphone class(마이크를 이용한 작업)

 

AND

<?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"

                     creationComplete="init();"

                     >

     

      <fx:Script>

            <![CDATA[

                  private function init():void

                  {

                        var s:Sound = new Sound(new URLRequest("test.mp3"));

                        s.play();

                  }

            ]]>

      </fx:Script>

</s:Application>

 

매우 간단합니다. 사운드 클래스에 URLRequest로 MP3파일 읽어와서 넘겨주면 끝~.

AND