윈도우즈의 경우 대상 윈도우의 Procedure로 바로 메시지가 디스패치되므로 메시지를 중간에 처리하려면 MessageHook이나 윈도우 SubClass를 사용해야 한다. (C++ 클래스로 구현할 경우 상위 클래스로 메시지를 전달하기 위해 virtual method 등의 언어적 특성을 이용해 메시지를 상위 클래스의 헨들러로 전달하는 방식으로 구현을 하게 된다. 하지만 모든 메시지 헨들러들을 이렇게 처리할 경우 vtable 관리에 부담이 생기는 단점이 발생한다. MFC같은 경우에는 이런 단점을 극복하기 위해서 Message Map과 같은 별도의 구현을 사용한다.) 하여간 안드로이드의 이벤트 전달 방식은 Java의 언어적인 측면과 어울러져 더 깔끔하게 정리된 형태로 보여진다.
안드로이드의 이벤트 처리 방식에는 윈도우즈와는 다른 특이한 점들이 있다. 이에 안드로이드의 이벤트 디스패치 단계를 정리 해보았다. (이런 정리 싫어하지만 기본기가 중요하므로 정리했다 --)
특히 터치 이벤트에서 ACTION_DOWN은 모든 핸들러의 단계를 거치게 되고 중간에 이를 처리하면, 이어지는 ACTION_MOVE, ACTION_UP 이벤트는 해당 위치까지만 디스패치 되고 그 메소드를 호출하는 구조이다. (여러 하위 구조를 가지는 복잡한 레이아웃에서는 이런 설계가 여러 핸들러를 거치는 오버헤드를 줄이는 효과가 있을 것이다.)
이벤트 전송의 간략한 메카니즘은 상위에서 하위의 dispatcher 호출을 통해서 이벤트가 아래로 전달되고, 최하위에서는 역으로 listener와 handler가 호출되며 dispatcher가 리턴되면서 하위에서 상위로 이벤트가 전달되는 스택 구조이다.
dispatchTouchEvent, onInterceptTouchEvent, onTouch(Listener) ,onTouchEvent 이 정도 메소드로 이벤트를 처리할 수 있는데, 이제부터 콜백 메소드에서 해당 터치 이벤트를 제어(handled, comsumed)할 경우 디스패치 단계가 어떻게 처리되는지 감상해보자...
ACTION_DOWN 이벤트는 각 단계를 모두 거치면서 자신의 이벤트 셋(DOWN, MOVE, UP)을 처리할 핸들러가 있는지 확인하게 된다.
위 이미지와 같이 특별히 이벤트를 처리하는 곳이 없으면 최상위의 Activity.onTouchEvent가 핸들러인 것 처럼 간주되어 이어지는 ACTION_MOVE와 ACTION_UP 이벤트는 Activity의 dispater에서 Activity의 핸들러로 바로 처리해 버린다.
실제 앱 구현시에는 대부분 위 이미지 중에 4번째 또는 7번째 이미지만 참고하면 될 것 같다.
그림으로 정리하니깐 분량이 많다 -_-; 하지만 다음의 룰을 따른다고 보면 간단하다.
onInterceptTouchEvent는 자식의 dispatchTouchEvent가 호출되야 한다면 그 직전에 항상 호출된다.
onTouch Listener는 onTouchEvent Handler가 호출되기 직전에 항상 호출된다.
Listener가 이벤트를 처리해서 true(consumed)를 리턴하면 이어지는 Handler는 호출되지 않는다.
dispatchTouchEvent는 하위의 dispatchTouchEvent를 호출한 이후에 자신의 Listener, Handler를 호출해서 이벤트를 전달한다.
하위의 dispatchTouchEvent가 true(consumed)를 리턴하면, 이어지는 자신의 Listener, Handler를 호출되지 않는다.
Listener 또는 Handler에서 ACTION_DOWN에 대해 true(consumed)를 리턴하면, 해당하는 dispatchTouchEvent도 true(consumed)를 리턴하게 된다.
위의 경우에 이어지는 ACTION_MOVE와 ACTION_UP은 해당 dispatchTouchEvent까지 전달되어 하위로 전달없이 바로 해당 Listener 또는 Handler를 호출한다.
* 특정 Listener 또는 Handler에서 ACTION_DOWN에 대해 true를 리턴한후 이어지는 ACTION_MOVE 또는 ACTION_UP에서 false를 리턴하면 어떻게 될까? 원래와 동일한 순서로 이벤트가 디스패치되며, 여기에 추가적으로 Activity.onTouchEvent에도 이벤트가 전달된다. 즉, 터치 이벤트의 원래 디스패치 설계 의도대로 이벤트 세트의 처리 단계를 ACTION_DOWN 이후에 나눌수 없다. (자꾸 윈도우즈 개념이 오버랩되다 보니.. 기껏 그림 그려가며 확인하고도.. 왜 이게 될 거라고 생각했을까 -_-?)
'Programming > Android' 카테고리의 다른 글
sendBroadcast와 startActivity의 차이 (0) | 2013.11.13 |
---|---|
GestureDetector 2 (0) | 2013.06.28 |
onTouch() 와 onTouchEvent() 가 호출되는 순서 (0) | 2013.01.29 |
BluetoothSocket의 연결 오류 (2) | 2012.08.24 |
갑자기 발생하는 java.lang.NoClassDefFoundError 에 대한 대책 (0) | 2012.05.03 |