이벤트 리스너

Flash Player 9 이상, Adobe AIR 1.0 이상

이벤트 리스너는 Flash Player 및 AIR에서 특정 이벤트에 대한 응답으로 실행되는 함수이며 이벤트 핸들러라고도 합니다. 이벤트 리스너를 추가할 때는 두 단계 과정을 거쳐야 하는데, 먼저 Flash Player 또는 AIR에서 이벤트에 대한 응답으로 실행할 함수 또는 클래스 메서드를 만듭니다. 이를 리스너 함수 또는 이벤트 핸들러 함수라고도 합니다. 그런 다음 addEventListener() 메서드를 사용하여 리스너 함수를 이벤트 대상 또는 적절한 이벤트 흐름을 따라 놓여 있는 표시 목록 객체에 등록합니다.

리스너 함수 만들기

리스너 함수 만들기는 ActionScript 3.0 이벤트 모델이 DOM 이벤트 모델과 다른 부분 중 하나입니다. DOM 이벤트 모델에서는 이벤트 리스너와 리스너 함수 간의 차이가 명확합니다. 이벤트 리스너는 EventListener 인터페이스를 구현하는 클래스의 인스턴스이고 리스너 함수는 handleEvent()라는 클래스의 메서드입니다. 또한 DOM 이벤트 모델에서는 실제 리스너 함수가 아니라 리스너 함수를 포함하는 클래스 인스턴스를 등록합니다.

반면에 ActionScript 3.0 이벤트 모델에서는 이벤트 리스너와 리스너 함수 간에 차이가 없습니다. ActionScript 3.0에는 EventListener 인터페이스가 없으며 리스너 함수를 클래스 외부에 또는 클래스의 일부로 정의할 수 있습니다. 또한 리스너 함수의 이름을 handleEvent()로 지정할 필요가 없으며 유효한 식별자를 사용하여 명명할 수 있습니다. ActionScript 3.0에서는 실제 리스너 함수의 이름을 등록한다는 것도 DOM 이벤트 모델과 다릅니다.

클래스 외부에 정의되는 리스너 함수

다음 코드에서는 빨간색 정사각형 모양을 표시하는 간단한 SWF 파일을 만듭니다. 여기에서 클래스 외부에 정의된 clickHandler() 리스너 함수는 빨간색 정사각형에서 마우스 클릭 이벤트를 수신합니다.

package 
{ 
    import flash.display.Sprite; 
 
    public class ClickExample extends Sprite 
    { 
        public function ClickExample() 
        { 
            var child:ChildSprite = new ChildSprite(); 
            addChild(child); 
        } 
    } 
} 
 
import flash.display.Sprite; 
import flash.events.MouseEvent; 
 
class ChildSprite extends Sprite 
{ 
    public function ChildSprite() 
    { 
        graphics.beginFill(0xFF0000); 
        graphics.drawRect(0,0,100,100); 
        graphics.endFill(); 
        addEventListener(MouseEvent.CLICK, clickHandler); 
    } 
} 
 
function clickHandler(event:MouseEvent):void 
{ 
    trace("clickHandler detected an event of type: " + event.type); 
    trace("the this keyword refers to: " + this); 
}

사용자가 사각형을 클릭하여 그 결과 나타나는 SWF 파일과 상호 작용하면 Flash Player 또는 AIR에서 다음과 같은 추적 출력이 생성됩니다.

clickHandler detected an event of type: click 
the this keyword refers to: [object global]

이벤트 객체는 clickHandler()에 인수로 전달됩니다. 이를 통해 리스너 함수에서 이벤트 객체를 검토할 수 있습니다. 이 예제에서는 이벤트 객체의 type 속성을 사용하여 이벤트가 click 이벤트인지 확인합니다.

또한 이 예제에서는 this 키워드의 값도 확인합니다. 이 경우에는 함수가 사용자 정의 클래스 또는 객체의 외부에 정의되므로 this가 전역 객체를 나타냅니다.

클래스 메서드로 정의되는 리스너 함수

다음 예제는 clickHandler() 함수가 ChildSprite 클래스의 메서드로 정의된다는 것만 제외하면 ClickExample 클래스를 정의하는 위의 예제와 같습니다.

package 
{ 
    import flash.display.Sprite; 
 
    public class ClickExample extends Sprite 
    { 
        public function ClickExample() 
        { 
            var child:ChildSprite = new ChildSprite(); 
            addChild(child); 
        } 
    } 
} 
 
import flash.display.Sprite; 
import flash.events.MouseEvent; 
 
class ChildSprite extends Sprite 
{ 
    public function ChildSprite() 
    { 
        graphics.beginFill(0xFF0000); 
        graphics.drawRect(0,0,100,100); 
        graphics.endFill(); 
        addEventListener(MouseEvent.CLICK, clickHandler); 
    } 
    private function clickHandler(event:MouseEvent):void 
    { 
        trace("clickHandler detected an event of type: " + event.type); 
        trace("the this keyword refers to: " + this); 
    } 
}

사용자가 빨간색 사각형을 클릭하여 그 결과로 나타나는 SWF 파일에 대해 작업을 처리하면 Flash Player 또는 AIR에서 다음과 같은 추적 출력이 생성됩니다.

clickHandler detected an event of type: click 
the this keyword refers to: [object ChildSprite]

여기에서 this 키워드는 child라는 ChildSprite 인스턴스를 참조하는데, 이는 ActionScript 2.0의 비헤이비어와 비교하여 달라진 점입니다. ActionScript 2.0 구성 요소를 사용한 경우, 클래스 메서드를 UIEventDispatcher.addEventListener()에 전달하면 메서드 범위가 리스너 메서드가 정의된 클래스 대신 이벤트를 브로드캐스팅하는 구성 요소에 바인딩되었음을 유념해야 합니다. 즉, ActionScript 2.0에서 이 방법을 사용한 경우에는 this 키워드가 ChildSprite 인스턴스 대신 이벤트를 브로드캐스팅하는 구성 요소를 참조합니다.

이렇게 되면 리스너 메서드를 포함하는 클래스의 다른 메서드 및 속성에 액세스할 수 없으므로 일부 프로그래머에게는 이것이 중요한 문제였고 이를 해결하기 위해 ActionScript 2.0 프로그래머는 mx.util.Delegate 클래스를 사용하여 리스너 메서드의 범위를 변경할 수 있었습니다. 그러나 ActionScript 3.0에서는 addEventListener()가 호출될 때 바인딩 메서드를 만들기 때문에 이 방법이 더 이상 필요하지 않습니다. 결과적으로 this 키워드는 child라는 ChildSprite 인스턴스를 참조하고 프로그래머는 ChildSprite 클래스의 다른 메서드와 속성에 액세스할 수 있습니다.

사용할 수 없는 이벤트 리스너

동적으로 지정된 리스너 함수를 가리키는 속성으로 일반 객체를 만드는 제 3의 방법이 있지만 사용하지 않는 것이 좋습니다. 이 방법은 ActionScript 2.0에서 일반적으로 사용되었기 때문에 여기에서 설명하지만 ActionScript 3.0에서는 사용하지 않아야 합니다. 이 방법을 사용하면 this 키워드가 리스너 객체 대신 전역 객체를 참조하므로, 권장할만한 방법은 아닙니다.

다음 예제는 리스너 함수가 myListenerObj라는 일반 객체의 일부로 정의된다는 것만 제외하면 위에 나오는 ClickExample 클래스 예제와 같습니다.

package 
{ 
    import flash.display.Sprite; 
 
    public class ClickExample extends Sprite 
    { 
        public function ClickExample() 
        { 
            var child:ChildSprite = new ChildSprite(); 
            addChild(child); 
        } 
    } 
} 
 
import flash.display.Sprite; 
import flash.events.MouseEvent; 
 
class ChildSprite extends Sprite 
{ 
    public function ChildSprite() 
    { 
        graphics.beginFill(0xFF0000); 
        graphics.drawRect(0,0,100,100); 
        graphics.endFill(); 
        addEventListener(MouseEvent.CLICK, myListenerObj.clickHandler); 
    } 
} 
 
var myListenerObj:Object = new Object(); 
myListenerObj.clickHandler = function (event:MouseEvent):void 
{ 
        trace("clickHandler detected an event of type: " + event.type); 
        trace("the this keyword refers to: " + this); 
}

추적 결과는 다음과 같습니다.

clickHandler detected an event of type: click 
the this keyword refers to: [object global]

this 키워드가 myListenerObj를 참조하고 추적 출력이 [object Object]로 표시된다고 예상할 수 있지만 실제로는 전역 객체를 참조합니다. 동적 속성 이름을 addEventListener()에 인수로 전달하면 Flash Player 또는 AIR에서 바인딩 메서드를 만들 수 없습니다. 이는 listener 매개 변수로 전달하는 대상이 리스너 함수의 메모리 주소이고 Flash Player 및 AIR에서는 해당 메모리 주소를 myListenerObj 인스턴스에 링크할 수 없기 때문입니다.

이벤트 리스너 관리

IEventDispatcher 인터페이스의 메서드를 사용하여 리스너 함수를 관리할 수 있습니다. IEventDispatcher 인터페이스는 DOM 이벤트 모델에서 사용되는 EventTarget 인터페이스의 ActionScript 3.0 버전입니다. IEventDispatcher라는 이름을 보면 이 인터페이스가 주로 이벤트 객체를 보내거나 전달하는 데 사용되는 것 같지만 실제로 이 클래스의 메서드는 이벤트 리스너를 등록, 확인 또는 제거하는 데 자주 사용됩니다. IEventDispatcher 인터페이스는 다음 코드와 같이 다섯 개의 메서드를 정의합니다.

package flash.events 
{ 
    public interface IEventDispatcher 
    { 
        function addEventListener(eventName:String,  
                        listener:Object, 
                        useCapture:Boolean=false, 
                        priority:Integer=0, 
                        useWeakReference:Boolean=false):Boolean; 
 
        function removeEventListener(eventName:String,  
                    listener:Object, 
                    useCapture:Boolean=false):Boolean; 
 
        function dispatchEvent(eventObject:Event):Boolean; 
 
        function hasEventListener(eventName:String):Boolean; 
        function willTrigger(eventName:String):Boolean; 
    } 
}

Flash Player API는 이벤트 대상 또는 이벤트 흐름 구성 요소일 수 있는 모든 클래스의 기본 클래스로 사용되는 EventDispatcher 클래스를 사용하여 IEventDispatcher 인터페이스를 구현합니다. 예를 들어 DisplayObject 클래스는 EventDispatcher 클래스에서 상속됩니다. 즉, 표시 목록의 모든 객체는 IEventDispatcher 인터페이스의 메서드에 액세스할 수 있습니다.

이벤트 리스너 추가

addEventListener()는 IEventDispatcher 인터페이스에서 많은 역할을 담당하는 중요한 메서드입니다. 이 메서드는 리스너 함수를 등록할 때 사용됩니다. 이때 typelistener라는 두 개의 매개 변수가 필요합니다. type 매개 변수는 이벤트 유형을 지정하는 데 사용되고, listener 매개 변수는 이벤트가 발생할 때 실행할 리스너 함수를 지정하는 데 사용됩니다. listener 매개 변수는 함수 또는 클래스 메서드에 대한 참조일 수 있습니다.

listener 매개 변수를 지정할 때 괄호를 사용하지 마십시오. 예를 들어 다음과 같이 addEventListener() 메서드를 호출하는 경우 clickHandler() 함수를 지정할 때 괄호를 추가하지 않습니다.
addEventListener(MouseEvent.CLICK, clickHandler)

addEventListener() 메서드의 useCapture 매개 변수를 사용하면 리스너를 활성화할 이벤트 흐름 단계를 제어할 수 있습니다. 예를 들어 useCapturetrue로 설정되면 이벤트 흐름의 캡처 단계를 진행하는 동안 리스너가 활성화되고, useCapturefalse로 설정되면 이벤트 흐름의 대상 단계 및 버블링 단계를 진행하는 동안 리스너가 활성화됩니다. 이벤트 흐름의 모든 단계를 진행하는 동안 이벤트를 수신하려면 addEventListener()를 두 번 호출해야 하는데, 첫 번째는 useCapturetrue로 설정하고 두 번째는 useCapturefalse로 설정해야 합니다.

addEventListener() 메서드의 priority 매개 변수는 DOM 레벨 3 이벤트 모델의 공식 구성 요소가 아닙니다. 이 매개 변수는 이벤트 리스너를 좀 더 융통성 있게 구성할 수 있도록 하기 위해 ActionScript 3.0에 포함되었습니다. addEventListener()를 호출하는 경우 정수 값을 priority 매개 변수로 전달하여 해당 이벤트 리스너의 우선 순위를 설정할 수 있습니다. 기본값은 0이지만 음의 정수 또는 양의 정수 값으로 설정할 수 있습니다. 이 값이 클수록 이벤트 리스너의 실행 순서가 빠릅니다. 우선 순위가 같은 이벤트 리스너는 추가된 순서대로 실행되므로 먼저 추가된 리스너의 실행 순서가 빠릅니다.

useWeakReference 매개 변수를 사용하면 리스너 함수에 대한 참조를 약한 참조 또는 일반 참조로 지정할 수 있습니다. 이 매개 변수를 true로 설정하면 더 이상 필요하지 않은 리스너 함수가 메모리에 남아있는 것을 방지할 수 있습니다. Flash Player 및 AIR에서는 가비지 컬렉션이라는 기법을 활용하여 더 이상 사용되지 않는 객체를 메모리에서 제거합니다. 객체에 대한 참조가 없는 경우 해당 객체는 더 이상 사용되지 않는 것으로 간주됩니다. 가비지 수집기는 참조가 약한 참조인지 여부에 관계없이 작업을 실행합니다. 즉, 약한 참조만 포함하는 리스너 함수를 가비지 컬렉션 대상으로 포함할 수 있습니다.

이벤트 리스너 제거

removeEventListener() 메서드를 사용하면 더 이상 필요하지 않은 이벤트 리스너를 제거할 수 있습니다. 더 이상 사용하지 않을 모든 리스너를 제거하는 것이 좋습니다. 이 메서드를 사용하는 경우에는 addEventListener() 메서드를 사용할 때와 마찬가지로 eventNamelistener 매개 변수가 반드시 필요합니다. 앞에서 설명했듯이 모든 이벤트 단계를 진행하는 동안 이벤트를 수신하려면 addEventListener()를 두 번 호출해야 하는데, 첫 번째는 useCapturetrue로 설정하고 두 번째는 false로 설정해야 합니다. 마찬가지로, 두 이벤트 리스너를 모두 제거하려면 removeEventListener()를 두 번 호출해야 하는데, 첫 번째는 useCapturetrue로 설정하고 두 번째는 false로 설정해야 합니다.

이벤트 전달

dispatchEvent() 메서드는 고급 프로그래머가 사용자 정의 이벤트 객체를 이벤트 흐름에 전달할 때 사용할 수 있습니다. 이 메서드에 사용할 수 있는 매개 변수는 이벤트 객체에 대한 참조뿐이며, 이는 Event 클래스의 인스턴스 또는 Event 클래스의 하위 클래스여야 합니다. 이벤트가 전달된 후 해당 이벤트 객체의 target 속성은 dispatchEvent()가 호출된 객체로 설정됩니다.

기존 이벤트 리스너 확인

IEventDispatcher 인터페이스의 마지막 두 메서드는 이벤트 리스너가 있는지 여부에 대해 유용한 정보를 제공합니다. 지정된 이벤트 유형의 이벤트 리스너가 특정 표시 목록 객체에 있는 경우 hasEventListener() 메서드에서 true를 반환합니다. 특정 표시 목록 객체에 리스너가 있는 경우 willTrigger() 메서드에서도 true를 반환하지만 willTrigger() 메서드는 해당 표시 객체뿐만 아니라 이벤트 흐름의 모든 단계에 대해 해당 표시 목록 객체의 모든 조상에서도 리스너를 확인합니다.

리스너가 없는 오류 이벤트

예외(이벤트 아님)는 ActionScript 3.0에서 오류 처리를 위한 주요 메커니즘으로 사용되지만 파일 로드와 같은 비동기 작업에는 예외 처리가 작동하지 않습니다. 이러한 비동기 작업을 실행하는 동안 오류가 발생하면 Flash Player 및 AIR에서는 오류 이벤트 객체를 전달합니다. 오류 이벤트에 대한 리스너를 만들지 않은 경우에는 Flash Player 및 AIR의 디버거 버전에서 오류 정보가 포함된 대화 상자가 표시됩니다. 예를 들어 응용 프로그램이 잘못된 URL에서 파일을 로드하려고 하면 Flash Player의 디버거 버전에 다음과 같이 오류를 설명하는 대화 상자가 표시됩니다.

대부분의 오류 이벤트는 ErrorEvent 클래스를 기초로 하며 Flash Player 또는 AIR에 표시되는 오류 메시지를 저장하는 데 사용되는 text 속성을 포함합니다. 이때 StatusEvent 클래스와 NetStatusEvent 클래스는 예외입니다. 이러한 두 클래스에는 모두 level 속성(StatusEvent.levelNetStatusEvent.info.level)이 있으며, level 속성의 값이 "error"이면 이러한 이벤트 유형이 오류 이벤트로 간주됩니다.

오류 이벤트가 발생해도 SWF 파일은 계속 실행됩니다. 이러한 오류 이벤트는 디버거 버전의 브라우저 플러그인과 독립 실행형 플레이어의 대화 상자, 제작 플레이어 출력 패널의 메시지, Adobe Flash Builder 로그 파일의 항목 등으로만 표시되며, 릴리스 버전의 Flash Player 또는 AIR에는 표시되지 않습니다.