본문 바로가기

Blog/Flex

SystemManager에 대하여

       

Flex Framework 에서 Application 컨테이너 컴포넌트가 생성 되는 과정을 살펴봅니다. 플래시에서는 swf가 실행되면 맨 처음으로 MainTimeLine 을 생성하지만 Flex 에서는 SystemManager 를 생성합니다. SystemManager는 두 프레임으로 이루어진 무비클립입니다. 두개의 프레임으로 구성된 이유는 일반적인 플레시 무비를 작성할 때와 같이 1프레임에서 초기화 상태를 체크하고 로딩 상태를 표시 한 후 2프레임으로 넘겨 본래의 컨텐츠를 실행시키는 작업 방식을 위해서입니다.

SystemManager가 두 프레임 무비클립이 되는 과정 (http://vulcan9.tistory.com/15 참고)

flex의 모든 컴포넌트들이 UIComponent à FlexSprite à Sprite 의 상속체인으로 한 개의 프래임만을 가지는 것과 달리 SystemManager 는 SystemManager à MovieClip à Sprite 의 체인으로 두개의 프레임을 갖습니다. 따라서 SystemManager (무비클립) 은 일단은 플래시의 MainTmeLine 의 역할(SystemManager Class는 플래시의Document Class 역할)과 함께 1프레임에서는 로딩상태를 표시하고 2프레임에서는 컨텐츠 (Application )을 표시하는 역할을 한다고 할 수 있습니다. 또한 구조상 항상 Application위에 표시되어야 하는 툴팁과 팝업을 포함하는 컨테이너 역할도 담당합니다.

그럼 SystemManager가 무슨 일을 하는지 순서대로 요약해 봅니다.

  • SWF 파일이 실행되어 SystemManager 의 인스턴스가 생성됩니다.
  • SystemManager 가 리소스 번들을 로드 합니다. 리소스 번들이란 다국어 지원 등을 위해 작성된 나라별로 분류된 텍스트 또는 파일 등을 통틀어 말합니다. – (Locale 참고)
  • SystemManager 의 1프레임에서 정지시킵니다. Preloader 인스턴스를 생성합니다.
  • 리소스 번들을 사용할 수 있도록 ResourceManager 클래스를 등록하고, HTML 로부터 전달되는 변수(FlashVar) 를 ResourceManager에 전달합니다. – 이제부터 ResourceManager를 사용할 수 있습니다. Preloader에 다국어로 표시해야 할 때도 있으므로 Preloader가 표시되기 전에 ResourceManager 를 사용 가능하도록 하는 것 같습니다.
  • SystemManager 가 Preloader 를 시작합니다. Preloader 가 RSL을 다운로드하면서 이벤트를 발생합니다. 다운로드 완료시 Preloader 가 initProgress 이벤트 발생시키면 SystemManager가 이를 받아 2프레임으로 이동합니다.
  • SystemManager 가 Application 객체를 인스턴스화 및 초기화합니다. Application 초기화 후 creationComplete 이벤트를 Preloader에 알리고, Preloader 는 초기화 완료 이벤트를 SystemManager에 알립니다.
  • Application 인스턴스를 자식으로 추가하고 Preloader는 제거합니다.
  • SystemManager 와 Application 객체가 applicationComplete 이벤트를 발생시킵니다.

     

[SystemManager 코드 분석]

플렉스 SWF 는 시작과 동시에 SystemManager 객체가 Stage에 생성됩니다. (Frame 메타태그에 의해서…) SystemManager 객체는 생성자에서 root.loaderInfo 변수에 이벤트를 설정하는데 이 loaderInfo에 이벤트를 설정하면 다운로드 상황을 모니터링 할 수 있겠죠. SystemManager가 Preloader 를 생성하고 작동시키는 방법입니다. 플래시에서 2프레임을 이용해 로딩 bar를 표시하는 방법과 흡사하죠.

참고로 LoaderInfo 클래스는 로드된 SWF 파일 또는 로드된 이미지 파일(JPEG, GIF, PNG)에 대한 정보를 제공합니다. LoaderInfo 객체에 엑세스하는 방법에는 두가지가 있습니다. Loader 객체의 contentLoaderInfo 속성은 Loader 객체가 로드 중인 내용에 대한 정보를 제공하는 반면, DisplayObject 의 loaderInfo 속성은 해당 표시 객체의 루트 SWF 파일에 대한 정보를 제공합니다. SWF 파일의 기본 클래스(MainTimeLine 또는 SystemManager) 인스턴스에서는 Loader 객체가 없으므로 loaderInfo 속성이 SWF 파일 기본 클래스 인스턴스의 LoaderInfo에 액세스할 수 있는 유일한 방법입니다.

그럼 SystemManager의 소스를 분석해 보면서 위 내용을 확인해 보겠습니다. 생성자로부터 시작해 주석을 쭉 읽어나가시면 실제 진행 순서대로 파악하실 수 있으리라 봅니다. 관심 밖의 코드는 모두 삭제되었습니다.

package mx.managers
{
    
public class SystemManager extends MovieClip implements IChildList, IFlexDisplayObject, IFlexModuleFactory, ISystemManager, ISWFBridgeProvider
    {
        // 모든 Flex application 의 시작점입니다. Flash Player가 생성자를 호출함으로써 Flex application이 시작됩니다.
        public function SystemManager()
        {
            
super();
            // stage 설정
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;

            // ResourceBundle 지정 (기본값 : "en_US")
            
            // 1프레임에 정지
            stop();
            
            // root 의 loaderInfo에 다운로드 시작 이벤트 받음
            root.loaderInfo.addEventListener(Event.INIT, initHandler);
        }
        
        
private function initHandler(event:Event):void
        {
            // SystemManager 인스턴스를 Dictionary 형태로 관리
            allSystemManagers[this] = this.loaderInfo.url;
            root.loaderInfo.removeEventListener(Event.INIT, initHandler);
            
            // docFrameListener 메서드는 2프레임이 되면 docFrameHandler를 호출하는 메서드임.
            addEventListener(Event.ENTER_FRAME, docFrameListener);
            
            // initialize 메서드 호출
            initialize();
        }

        // Preloader인스턴스를 생성하고 child로 추가한다.
        mx_internal function initialize():void
        {
            // Preloader인스턴스를 생성. stage에 추가한다.
            preloader = new Preloader();

            // 이벤트 등록. 다운로드가 완료된 후 application 인스턴스 생성을 위해 한번 호출되는 이벤트 들임.
            preloader.addEventListener(FlexEvent.INIT_PROGRESS, preloader_initProgressHandler);
            preloader.addEventListener(FlexEvent.PRELOADER_DONE, preloader_preloaderDoneHandler);
            
            // child 추가
            _popUpChildren = new SystemChildrenList(this, new QName(mx_internal, "noTopMostIndex"), new QName(mx_internal, "topMostIndex"));
            _popUpChildren.addChild(preloader);
            
            // info의 내용에 따라 RSL 목록 작성
            
            // ResourceManager class를 singleton 생성
            // 다른 singleton class들을 등록한다.
            // IEmbeddedFontRegistry, IStyleManager, IStyleManager2
            // 다른 manager들은 나중에 2프레임에서 docFrameHandler 메서드에서 등록한다.
            
            // SWF를 담고있는 HTML의 FlashVars 또는 SWF URL의 query 인자로 부터 ResourceManager의 localeChain 설정값 조사
            // resource module 의 URL 목록 작성
            
            // preloader. 초기화
            preloader.initialize(......);
        }

        // swf 가 다운로드 완료되었으므로 다음 프레임으로 이동한다.
        private function preloader_initProgressHandler(event:Event):void
        {
            // 2프레임으로 이동
            deferredNextFrame();
        }
        
        // 2프레임이 되었으므로 다음 메서드가 실행됨.
        // 다운로드가 완료되어 Player에 의해 application 클래스가 정의된 상태이므로 Application 객체를 생성할 수 있다.
        mx_internal function docFrameHandler(event:Event = null):void
        {
            // ResourceManager는 1프레임에서 initialize() 메서드에 의해 이미 등록되었다.
            // 다른 singleton class들을 등록한다.
            // IBrowserManager, ICursorManager, IHistoryManager, ILayoutManager, IPopUpManager, IToolTipManager2, DragManager
            
            
// SWF를 담고있는 HTML의 FlashVars 또는 SWF URL의 query 인자로 부터 조사한 ResourceManager의 localeChain 값에 따라 설정한다.
            // 만약 compiled 옵션이 -locale=en_US,ja_JP 이고, Capabilities.languages 값이 [ "ja-JP" ] 라면 localeChain 값은 [ "ja_JP" "en_US" ]가 된다.
            installCompiledResourceBundles();
            
            
// Application 객체 인스턴스화
            initializeTopLevelWindow(null);
        }
        
        
// SystemManager 의 child로 추가한다.
        private function initializeTopLevelWindow(event:Event):void
        {
            
// _topLevelSystemManager 설정
            
            
// create() 메서드로 사용자가 작성한 Application 파생 클래스의 인스턴스를 생성한다.
            // 생성된 application 객체를 topLevelWindow와 document로 등록 한다.
            document = app = topLevelWindow = IUIComponent(create());
            
            
// application 의 creationComplete 이벤트를 등록
            IEventDispatcher(app).addEventListener(FlexEvent.CREATION_COMPLETE, appCreationCompleteHandler);
            
            
// preloader에 application객체를 알려준다.
            preloader.registerApplication(app);
            
            
// application 객체의 createChildren() 메서드가 호출된다.
            childAdded(DisplayObject(app));
        }
        
        
// UIComponent 역시 childAdded()메서드에서 아래와 같은 형식으로 child를 생성하는 구조로 되어있다.
        mx_internal function childAdded(child:DisplayObject):void
        {
            
// FlexEvent.ADD 이벤트 호출
            child.dispatchEvent(new FlexEvent(FlexEvent.ADD));

            
// application 객체의 initialize() 호출. initialize() 메서드는 createChildren()을 호출하여 child를 생성하기 시작함.
            IUIComponent(child).initialize();
        }
        
        
// preloader를 제거하고 application을 child로 추가한다.
        private function preloader_preloaderDoneHandler(event:Event):void
        {
            
// preloader 제거
            _popUpChildren.removeChild(preloader);
            preloader =
null;

            
// mouseCatcher를 child 0으로 추가
            mouseCatcher = new FlexSprite();
            mouseCatcher.name =
"mouseCatcher";
            
super.addChildAt(mouseCatcher, 0);

            
// application을 child 1로 추가, application 의 root, stage, parent 속성이 채워짐.
            super.addChildAt(DisplayObject(app), 1);

            
// applicationComplete 이벤트 발생.
            app.dispatchEvent(new FlexEvent(FlexEvent.APPLICATION_COMPLETE));
            dispatchEvent(
new FlexEvent(FlexEvent.APPLICATION_COMPLETE));

        }
        

    }
}

 APPLICATION_COMPLETE 이벤트 이전에 root, stage, parent 속성을 참조하면 null 값이 리턴됩니다. 또한 이 상태는 swf를 로드해서 사용하는 경우 첫 프레임이 재생되기 전이기 때문에 1 프레임에 있는 객체를 참조할 수 없는 상태입니다. 이런 경우엔 APPLICATION_COMPLETE 이벤트에서 callLater 콜백함수를 등록해 사용하면 됩니다. callLater 함수는 1 프레임이 재생된 후 호출됩니다.

applicationComplete = "callLater(핸들러)"

어떻게 SystemManager의 생성자가 Flex application 의 시작점이 되는지에 대한 자세한 사항은 여기 (http://vulcan9.tistory.com/15) 를 참고하세요

     

[참고]
한국어판 Programming Flex3 - 체이픽 커준 조이 로트 | 김지원 옮김
Flex/AIR Bible -
윤훈남 지음

Flash Player의 관점에서 Flex의 초기화 과정 이해하기1
http://blog.naver.com/jjoommnn/130071247417

Flash Player의 관점에서 Flex의 초기화 과정 이해하기2
http://blog.naver.com/jjoommnn/130071825042