본문 바로가기
안드로이드

안드로이드의 Touch Event 디스패치 단계

by 호군 2011. 12. 13.
반응형

원문 : http://blog.naver.com/iwillhackyou/110106725477

TouchEvent가 발생하는 흐름(순서)를 알고 싶어서.. 보게된 블로그 입니다.
그림만 보고 이해하려고 했지만, 잘 이해가 가지 않더군요. 그냥 이런 순서로 가나보구나..하지만..
정확한 흐름을 이해하지 못했습니다.
그래서 안드로이드 프레임워크 소스를 봤습니다. 만약 그림을 봐도 이해가 되지 않는 분들은 소스를 보기를 추천합니다. 그러면 그림이 이해가 잘 될꺼라고 단언합니다.

그림으로 보실 분들을 위해서 그림에 대해서 몇가시 말씀드리겠습니다.
위에 있는 ViewGorup.dispatchTouchEvent()가 아래의 ViewGorup.dispatchTouchEvent() 사이에 --------> (점선화살표)로 된 선이 보이십니까?
이 부분은 '메소드 영역'입니다. 하나의 함수라는 의미 입니다.
즉, ViewGroup.dispatchTouchEvent() 메소드 안에서 ViewGroup.onInterceptTouchEvent를 호출하고, 이 반환값에 따라 자신의 ChildView들의 TouchEvent를 실행할지를 결정합니다. 만약 false를 반환하게되면, 순차적으로 자신의 ChildView들의 dispatchTouchEvent()를 호출합니다. 이중 자식중 true를 호출하게 되면 그 ViewGroup에서는 더 이상 KeyEvent가 발생하지 않습니다.  

그리고 Sequence1은 Down, Sequence2는 Move, Sequence3는 Up 동작을 나타냅니다.

사실 아래 그림은 전체 Flow를 나타내는 그림은 아닙니다. 그러나 우리가 제어 할 수 있는 부분을 모두 나타내고 있습니다. (전 그렇게 보고있습니다) 
그래도 소스를 보시면 더 좋겠죠. 또한 더 분명이 파악 하실 수 있으실 겁니다.



윈도우즈의 경우 대상 윈도우의 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 이후에 나눌수 없다. (자꾸 윈도우즈 개념이 오버랩되다 보니.. 기껏 그림 그려가며 확인하고도.. 왜 이게 될 거라고 생각했을까 -_-?)

반응형