태터데스크 관리자

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

태터데스크 메시지

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

[Flex] EventListener 는 되도록 적게 만들자.

2007/09/27 14:04

 

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

Event를 사용하다보면 나도 모르게 Listener를 비효율적으로 사용하는 경우가 있어서 정리해보았다.

Canvas위에 버튼 5개가 있다고 가정하자.
이 버튼은 addChild()에 의해 동적으로도 생성할 수 있을것이다.
아무튼 나도 모르게 다음과 같이 코딩하는 것을 발견할 수 있었다.

아주 비효율적으로 이벤트 청취자를 사용하는 방법 (Language : xml)
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*" layout="absolute" creationComplete="init()">
    <mx:Script>
        <![CDATA[
            private function init():void
            {
                button1.addEventListener(MouseEvent.CLICK, clickHandler1, false);
                button2.addEventListener(MouseEvent.CLICK, clickHandler2, false);
                button3.addEventListener(MouseEvent.CLICK, clickHandler3, false);
                button4.addEventListener(MouseEvent.CLICK, clickHandler4, false);
                button5.addEventListener(MouseEvent.CLICK, clickHandler5, false);
            }
           
            private function clickHandler1( e:MouseEvent ):void
            {
                trace(e.type, e.currentTarget.name,  e.target.name, e.eventPhase);
            }

            private function clickHandler2( e:MouseEvent ):void
            {
                trace(e.type, e.currentTarget.name,  e.target.name, e.eventPhase);
            }

            private function clickHandler3( e:MouseEvent ):void
            {
                trace(e.type, e.currentTarget.name,  e.target.name, e.eventPhase);
            }

            private function clickHandler4( e:MouseEvent ):void
            {
                trace(e.type, e.currentTarget.name,  e.target.name, e.eventPhase);
            }

            private function clickHandler5( e:MouseEvent ):void
            {
                trace(e.type, e.currentTarget.name,  e.target.name, e.eventPhase);
            }

        ]]>

    </mx:Script>

    <mx:Canvas id="canvas" x="19" y="10" width="386" height="50">
        <mx:Button id="button1" x="10" y="10" label="Button"/>
        <mx:Button id="button2" x="83" y="10" label="Button"/>
        <mx:Button id="button3" x="156" y="10" label="Button"/>
        <mx:Button id="button4" x="229" y="10" label="Button"/>
        <mx:Button id="button5" x="302" y="10" label="Button"/>
    </mx:Canvas>
</mx:Application>


어찌 생각되는가? 버튼 한개씩 만들때마다 이벤트 청취자(EventListener)를 생성한다. 이렇게 되면 프로그램이 실행될때 이벤트청취자가 5개 등록되므로 그만큼 시스템에 무리를 줄 수 있다.

그럼 다음처럼 해보자!

이벤트 핸들러 메소드를 1개로 줄임 (Language : xml)
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*" layout="absolute" creationComplete="init()">
    <mx:Script>
        <![CDATA[
            private function init():void
            {
                button1.addEventListener(MouseEvent.CLICK, clickHandler, false);
                button2.addEventListener(MouseEvent.CLICK, clickHandler, false);
                button3.addEventListener(MouseEvent.CLICK, clickHandler, false);
                button4.addEventListener(MouseEvent.CLICK, clickHandler, false);
                button5.addEventListener(MouseEvent.CLICK, clickHandler, false);
            }
           
            private function clickHandler( e:MouseEvent ):void
            {
                trace(e.type, e.currentTarget.name,  e.target.name, e.eventPhase);
               
                if( e.type != MouseEvent.CLICK ) return;
                switch( e.target.name )
                {
                    case "button1":
                        trace("button1을 눌렀을때 처리");
                        break;
                    case "button2":
                        trace("button2을 눌렀을때 처리");
                        break;
                    case "button3":
                        trace("button3을 눌렀을때 처리");
                        break;
                    case "button4":
                        trace("button4을 눌렀을때 처리");
                        break;
                    case "button5":
                        trace("button5을 눌렀을때 처리");
                        break;
                }
            }
        ]]>

    </mx:Script>

    <mx:Canvas id="canvas" x="19" y="10" width="386" height="50">
        <mx:Button id="button1" x="10" y="10" label="Button"/>
        <mx:Button id="button2" x="83" y="10" label="Button"/>
        <mx:Button id="button3" x="156" y="10" label="Button"/>
        <mx:Button id="button4" x="229" y="10" label="Button"/>
        <mx:Button id="button5" x="302" y="10" label="Button"/>
    </mx:Canvas>
</mx:Application>


위 코드는 전하고 다르게 핸들러 함수를 한개로 만들었다. switch문을 통해 해당버튼에 대한 처리를 하고 있다.
하지만 이벤트 청취자는 아직도 5개가 등록되어 있다.

여기서 우리는 이벤트 흐름에 대한 이해가 있다면 이벤트 청취자를 1개로 줄일 수 있다.
이벤트 흐름은 기본적으로 capture단계, target단계, bubble단계가 있다는 것을 아는 것이 중요하겠다.
이에 대한 자세한 내용은 이벤트 전파를 읽어보길 바란다.

버튼을 마우스 Click하게 되면 마우스 Click은 기본적으로 bubble단계로의 이벤트 전파가 되도록 되어 있으므로(http://flexdocs.kr/docs/flex2/langref/flash/display/InteractiveObject.html#event:click 를 참고) 버튼을 Box나 Canvas등으로 묶어 놓으면 이들에게도 이벤트가 전파된다. 이 아이디어를 가지고 있으면 5개 버튼에 모두 이벤트 청취자를 둘 것 없이 버튼을 자식(child)으로 둔 Canvas나 Box에만 이벤트 청취자를 두어도 상관없다.

아래 예제를 보자.

최적화된 이벤트 청취자 (Language : xml)
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*" layout="absolute" creationComplete="init()">
    <mx:Script>
        <![CDATA[
            private function init():void
            {
                canvas.addEventListener(MouseEvent.CLICK, clickHandler, false);
            }
           
            private function clickHandler( e:MouseEvent ):void
            {
                trace(e.type, e.currentTarget.name,  e.target.name, e.eventPhase);
               
                if( e.type != MouseEvent.CLICK ) return;
                switch( e.target.name )
                {
                    case "button1":
                        trace("button1을 눌렀을때 처리");
                        break;
                    case "button2":
                        trace("button2을 눌렀을때 처리");
                        break;
                    case "button3":
                        trace("button3을 눌렀을때 처리");
                        break;
                    case "button4":
                        trace("button4을 눌렀을때 처리");
                        break;
                    case "button5":
                        trace("button5을 눌렀을때 처리");
                        break;
                }
            }
        ]]>

    </mx:Script>

    <mx:Canvas id="canvas" x="19" y="10" width="386" height="50">
        <mx:Button id="button1" x="10" y="10" label="Button"/>
        <mx:Button id="button2" x="83" y="10" label="Button"/>
        <mx:Button id="button3" x="156" y="10" label="Button"/>
        <mx:Button id="button4" x="229" y="10" label="Button"/>
        <mx:Button id="button5" x="302" y="10" label="Button"/>
    </mx:Canvas>
</mx:Application>

자 어떠한가. 2번째 예제하고 다르게 한개의 청취자로 여러개의 버튼에서 Dispatch되는 마우스Click  이벤트를 처리하고 있다. 실행해보면 알겠지만 버튼 Click시 target은 항상 button이 되고 currentTarget은 canvas가 된다. 두번째 예제에서는 이와 다르게 target과 currentTarget이 모두 button이다.

또 한가지 확인할 것은 eventPhase다 capture가 1, target이 2, bubble이 3이다. 두번째, 세번째에서 이 값이 어떻게 나오는지 확인해보자. 그리고 왜 그렇게 나오는지 생각해보자.

앞서 언급했듯이 위 예제를 이해하기 위해서는 반드시 이벤트 전파에 대한 이해가 필요하다.
예제는 단지 이벤트 전파에 대한 일부만 소개했을 뿐이다. 이벤트 전파에대한 정확한 메카니즘을 알기 위해
아래 링크를 숙지할 필요가 있으며 자기만의 예제 프로그램을 만들어 볼 것을 권장한다.

이벤트 전파 - http://flexdocs.kr/docs/flex2/docs/00000475.html

글쓴이 : 지돌스타(http://blog.jidolstar.com/230)

크리에이티브 커먼즈 라이선스
Creative Commons License

Adobe Flash Platform , , ,

Trackback 주소: http://blog.jidolstar.com/trackback/230
  1. Blog Icon
    째코

    버블이 이럴 때 유용하군요
    하지만 각 버튼들이 무엇을 하는지가 중요한 포인트가 될 수도 있을거 같군요..
    특정부분만 달라질정도로 비슷하거나
    같은 작업을 하는거라면 아주 좋은 방법일 테지만
    전혀 다른 별개의 작업을 할경우에 하나의 핸들러는
    매우 길어질것이고 버튼*n개의 일을 처리 할것입니다
    리팩토링이냐 리소스효율성이냐는 그때 그때 잘 판단해야
    될듯 합니다.

  2. 째코님의 의견에 동감하는 바입니다.
    제가 쓴글이 정답이 될 수는 없지요.
    여러상황에서 적절하게 사용하도록 해야겠습니다.
    의견주셔서 감사해요~ ^^

  3. 유용한 정보 감사합니다~ㅋ
    제가 알고 있던거보다 훨씬 복잡한 메카니즘이네요..;
    아 그리고 홈피에 방명록 남겨주신거 잘 봤습니다^^ (꾸벅)

  4. ㅎㅎ 잘 만드셨던데요~
    더욱 멋진 홈피 기대할께욤~ ^^

  5. 버블링을 저렇게 쓰면 되는군요. ㅋ
    이벤트때문에 골머리 썩을때 봤던 부분이라 이해 못하고 그냥 넘어갔었는데 ㅋ

    근데 질문!
    id와 name은 어떻게 다른걸까요? ㅡㅡ;
    name은 왜 있는거죠? 갑자기 궁금해졌음.;

  6. Blog Icon
    째코

    id는 유일값이고 name이 설정되어 있지 않았을 경우
    해당 컴포넌트의 name은 id를 가져옵니다
    하지만 id 와 name이 둘다 설정되어 있다면
    name을 가져옵니다
    차이점이라면 id는 유일하고 name은 중복이 가능하다는점

  7. 감사감사~ :)

  8. Blog Icon
    T

    악플은 아니지만 말하기 편한 말식으로 말씀드리자면..
    코드의 가독성 유지보수성은 첫번째가 가장 좋아보이는 군요. 좀 더 제가 선호하는 스타일은 mxml상에서 이벤트리스너를 코딩하는 것이지만요.. <... click="어쩌고()/> 이런식으로..
    후자 처럼하였을대 과연 사용자가 느끼는 성능개선이 어느정도일지 의문입니다.
    이벤트 버블링에 대한 예제로서는 좋군요..

  9. 전 T님께서 쓰는 방식은 개인적으로 선호하는 방식이지 유지보수성을 위한 방식은 아니라고 생각합니다. 왜냐하면 mxml에서 쓰는 방식은 만들기 쉽지만 코드가 길어질경우 접근이 더 어려워집니다. AS3, mxml장단점을 잘 살려서 만들어야하는 이유가 여기에 있는 것이지요.

    아래 방식은 성능개선도 한몫할 것이라 생각하는데요. 리스너를 너무 많이 만들어놓으면 그 만큼 성능이 떨어지기 마련입니다.

    성능개선을 위해서는 여러가지를 고려해야할겁니다. 어떤식으로 구현할 것이냐에 따라서 선택하면 되는 것이지요. mxml상에 리스너를 등록하는 방식은 동적으로 삭제하기 힘듭니다. 하지만 AS3에서는 그것이 가능하지요. 동적으로 해야되는 경우라면 당연히 후자로 해야합니다. 객체마다 리스너를 등록하는 것은 좋지 못합니다.

    event 전달방식에 따라서 bubbling을 할거냐 말거냐는 선택해야겠습니다. event 정지 함수를 이용하면 포퍼먼스 올리는데 도움이 될 것이라 생각합니다.

  10. 글쎄요. 저게 버블링 예제라고 할 수 있을까요.
    제가 볼땐 버블링하고는 아무 상관 없어보이는데요.

    효율적인 이벤트 사용법은 맞군요.

  11. 버블링때문에 마우스 이벤트가 부모-자식간에 전달된 다는 것을 이용하는 예제지요.

  12. Blog Icon
    뒹굴뒹굴

    자료 감사합니다.
    이벤트에 대해서 정리를 하던 참이었는데
    많은 도움이 되었습니다 ^^

  13. Blog Icon
    나그네

    좋은 글 감사합니다.

  14. Blog Icon
    키보더

    난무하는 이벤트리스너때문에 어떻게 해야하나 생각하던차에 좋은자료 보고갑니다.