Android 이벤트 배포 메커니즘 3 : 이벤트 배포 워크 플로

머리말

만나서 반가워요 ~

이 기사는 이벤트 배포 시리즈의 세 번째입니다.

처음 두 기사에서 Android 이벤트 배포 메커니즘 1 : 이벤트가 활동에 어떻게 도달합니까? 이벤트 배포의 실제 시작점 분석 : viewRootImpl, Activity는 링크 중 하나 일뿐입니다 .Android 이벤트 배포 메커니즘 2 : 이벤트의 viewGroup 및보기 처리 소스 코드는 viewGroup 및 view가 이벤트를 배포하는 방법을 분석합니다.

이벤트 배포의 핵심 내용은 두 번째 기사 인 viewGroup 및 view 별 이벤트 배포입니다. 두 번째 기사에서는 소스 코드를 심도있게 분석하고 이벤트 배포 프로세스를 검토 할 수있는 높은 관점이 부족합니다. 이전 분석을 기반으로이 기사에서는 이벤트 배포의 전체 워크 플로를 요약하여 서로 다른 개체와 메서드간에 이벤트가 전달되는 방식을 더 잘 이해합니다.

리뷰

우리의 지식을 더 잘 포지셔닝하기 위해 먼저 전체 프로세스를 검토하겠습니다.

  1. 휴대폰이 화면을 터치하면 터치 정보가 생성되어 IMS 및 WMS를 통해 viewRootImpl로 전송됩니다.
  2. viewRootImpl은 뷰의 dispatchPointerEvent 메서드를 호출하여 터치 정보를 뷰에 전달합니다.
  3. 뷰는 자체 dispatchTouchEvent 메서드를 호출하여 이벤트 배포를 시작합니다.

그림의보기는 viewGroup 또는 단순보기 일 수있는 제어 트리를 참조합니다. viewGroup은 뷰에서 상속되기 때문에 컨트롤 트리도 뷰로 간주 될 수 있습니다.

오늘 논의하는 워크 플로는 그림의 뷰가 자신을 호출하는 dispatchTouchEvent로 시작됩니다.

주요 목적 및 방법

이벤트 전달 객체

내용의이 부분은 두 번째 장에서 자세히 분석되며 여기에 간략한 검토가 있습니다.

휴대폰이 화면을 터치하면 일련의 MotionEvent 객체가 생성되며, 터치 상황에 따라 이러한 객체의 유형이 달라집니다. 다음과 같이 세부 사항 :

  • ACTION_DOWN : 손가락이 화면을 누르는 것을 나타냅니다.
  • ACTION_MOVE : 손가락이 화면에서 미끄러지면 일련의 MOVE 이벤트가 생성됩니다.
  • ACTION_UP : 손가락을 떼고 화면을 떠나
  • ACTION_CANCEL :이 유형의 이벤트는 비정상적인 상황에서 이벤트 시퀀스가 ​​중단 될 때 생성됩니다.
  • ACTION_POINTER_DOWN : 이미 눌러 진 손가락이있는 경우 다른 손가락을 눌러이 이벤트를 생성합니다.
  • ACTION_POINTER_UP : 여러 손가락을 동시에 누르면 한 손가락을 떼면 이벤트가 생성됩니다.

이벤트 배포 방법

이벤트 배포는 제어 시스템의 일부이며 주요 배포 개체는 viewGroup 및 view입니다. 세 개의 코어가있는 dispatchTouchEvent방법 : onInterceptTouchEvent, onTouchEvent,. 따라서 배포 프로세스에 대해 이야기하기 전에이 세 가지 방법을 소개하겠습니다. 이 세 가지 메서드는 시스템의 클래스 뷰에 속하며, 인터페이스에는 Window.CallBack이 포함되어 dispatchTouchEvent있고 onTouchEvent메서드, Activity 및 Dialog는 Window.CallBack 인터페이스를 달성하고 메서드를 구현합니다. 이 세 가지 방법은 종종 사용자 정의보기에서 다시 작성되기 때문에 달리 지정하지 않는 한 다음 분석은 모두 기본 방법으로 구현됩니다.

dispatchTouchEvent

이 방법은 이벤트 배포의 핵심 방법이며 이벤트 배포의 논리가이 방법으로 구현됩니다. 이 메서드는 View 클래스에 있으며 하위 클래스 ViewGroup 및 DecorView와 같은 기타 구현 클래스가이 메서드를 재정의합니다.

viewGroup 또는 view에서이 메소드의 주요 기능은 이벤트를 처리하는 것입니다. 처리가 성공하면 true를 반환하고 처리가 실패하면 false를 반환하여 이벤트가 처리되지 않았 음을 나타냅니다. 클래스에 따라 viewGroup 관련 클래스에서이 메서드의 주요 기능은 viewGroup이 소유 한 자식 뷰에 이벤트를 배포하고 자식 뷰가 처리하지 않으면 자체적으로 처리하는 것입니다. 뷰 관련 클래스에서 ,이 방법의 주요 기능은 터치 이벤트 사용입니다.

onInterceptTouchEvent

이 메소드는 viewGroup에만 존재하며, 이벤트가 child view에 분배되어야 할 때 viewGroup은이 메소드를 호출하여 인터셉트 여부를 확인합니다. 인터 셉션 프로세스를 소유하고있는 경우, 아이가 dispatchTouchEvent이벤트를 배포하는 방법의 보기를 차단하지 않으면 호출됩니다 .

이 메서드는 이벤트를 가로 채려면 true를 반환하고 가로 채지 않으려면 false를 반환합니다.

기본적으로이 메서드는 마우스 관련 작업의 특수한 경우 만 가로 채고 다른 경우에는 가로 채기를 재정의하기 위해 특정 구현 클래스가 필요합니다.

onTouchEvent

이 메서드는 이벤트를 소비하는 주요 메서드이며 뷰에 존재합니다. ViewGroup은 기본적으로이 메서드를 재정의하지 않습니다. 이 메서드는 이벤트가 사용되었음을 나타 내기 위해 true를 반환하고 이벤트가 사용되지 않았 음을 나타 내기 위해 false를 반환합니다.

viewGroup이 이벤트를 분배 할 때 이벤트를 소비 할 자식 뷰가 없으면 자체 onTouchEvent 메서드를 호출하여 이벤트를 처리합니다. View의 dispatchTouchEvent 메서드에서는 이벤트를 소비하기 위해 onTouchEvent 메서드를 직접 호출하는 대신 먼저 onTouchListener를 호출하여 소비할지 여부를 결정합니다. onTouchListener가 이벤트를 소비하지 않으면 onTouchEvent를 호출하여 이벤트를 처리합니다.

뷰에 대해 설정 한 onClickListener 및 onLongClickListener는 모두 특정 터치 조건에 따라 뷰의 dispatchTouchEvent 메서드에서 호출됩니다.

중요한 규칙

이벤트 분배에는 매우 중요한 원칙이 있습니다. 터치 포인트의 이벤트 시퀀스는 viewGroup에 의해 가로채는 것과 같은 비정상적인 상황이 발생하지 않는 한 하나의 뷰에서만 소비 될 수 있습니다 . 구체적인 코드 구현은 다음과 같습니다. 터치 포인트 이벤트 시퀀스의 다운 이벤트를 소비하는 뷰는 터치 포인트 이벤트 시퀀스의 모든 후속 이벤트를 계속 소비합니다 . 밤을주세요 :

내 손가락이 화면을 누르면 다운 이벤트가 발생하고 하나의 뷰만 다운 이벤트를 소비하게되며, 그러면 내 손가락이 화면을 미끄러지면서 생성 된 이동 이벤트가이 뷰만 소비하게됩니다. 그리고 휴대폰을 다시 눌렀을 때 새로운 다운 이벤트가 발생하므로 이번에는 다시 다운 이벤트를 소비하는 뷰를 찾아 보도록하겠습니다. 따라서 이벤트 분배는 이벤트 순서를 기반으로합니다 .

따라서 다음 워크 플로는 ACTION_MOVE 또는 ACTION_UP 의 배포 가 아니라 다운 이벤트의 배포를 참조합니다 . down 이벤트가 소비되기 때문에 다음 move 및 up 이벤트가이 뷰에 의해 처리되며 배포 여부는 중요하지 않습니다. 그러나 동시에 이벤트 시퀀스는 viewGroup의 onInterceptTouchEvent에 의해 중단 될 수 있으며 이는 다른 상황에 속합니다.

세심한 독자는 이벤트 배포에 멀티 터치가 포함되어 있음을 알게 될 것입니다. 멀티 터치의 경우 ACTION_POINTER_DOWN과 ACTION_DOWN의 분배 규칙이 다르므로 자세한 내용은 두 번째 기사를 참조하십시오. ACTION_POINTER_DOWN은 ACTION_DOWN 배포 모델에서 약간 수정되어 나중에 자세히 분석됩니다.

워크 플로 모델

워크 플로 모델은 기본적으로 서로 다른 제어 개체, viewGroup 및보기 이벤트 배포 방법 간의 관계입니다. 여기서 논의되는 것은 viewGroup 및 view의 기본 메서드 구현이며 DecorView와 같은 다른 구현 클래스의 메서드를 재정의하지 않습니다.

다음 의사 코드는 세 가지 이벤트 배포 방법 간의 관계를 나타내는 데 사용됩니다 ( 여기서도 여기서 이벤트 배포 모델에 의해 배포 된 이벤트 유형은 ACTION_DOWN이며 모두 기본 방법이며 다시 작성하지 않고도 매우 중요합니다 ).

public boolean dispatchTouchEvent(MotionEvent event){
    
    
    
    // 先判断是否拦截
    if (onInterceptTouchEvent()){
    
    
        // 如果拦截调用自身的onTouchEvent方法判断是否消费事件
        return onTouchEvent(event);
    }
    // 否则调用子view的分发方法判断是否处理事件
    if (childView.dispatchTouchEvent(event)){
    
    
        return true;
    }else{
    
    
        return onTouchEvent(event);
    }
}

이 코드는 세 가지 메소드 간의 매우 좋은 관계를 보여줍니다. viewGroup이 터치 이벤트를 수신 할 때 onInterceptTouchEvent, 인터셉트가 onTouchEvent이벤트를 처리하기 위해 자신의 메소드를 호출하거나 dispatchTouchEventDistribute에 대한 서브 뷰 접근법을 호출하는 경우 인터 셉션 여부를 판별 하기 위해 메소드를 호출합니다. 이벤트. 하위보기도 viewGroup 일 수 있으므로 순환 관계가 형성됩니다.

여기에 뷰 배포 논리의 단순화 된 의사 코드를 추가합니다.

public boolean dispatchTouchEvent(MotionEvent event){
    
    
    // 先判断是否存在onTouchListener且返回值为true
    if (mOnTouchListener!=null && mOnTouchListener.onTouch(event)){
    
    
        // 如果成功消费则返回true
        return true;
    }else{
    
    
        // 否则调用onTouchEvent消费事件
        return onTouchEvent(event);
    }
}

view와 viewGroup의 차이점은 이벤트를 전달할 필요가 없기 때문에 이벤트를 가로 챌 필요가 없다는 것입니다. 뷰는 먼저 onTouchListener가 있고 반환 값이 true인지 확인합니다. true이면 직접 반환하고, 그렇지 않으면 onTouchEvent 메서드를 호출하여 이벤트를 처리합니다.

위의 관계를 바탕으로 다음 작업 흐름 차트를 얻을 수 있습니다.

클래스 재귀 관계를 보여주기 위해 여기에 두 개의 viewGroup이 그려져 있습니다. 가운데 하나만보세요.이 그림의 분석은 다음과 같습니다.

  • viewGroup
    1. viewGroup의 dispatchTouchEvent 메소드가 이벤트 메시지를 수신하면 먼저 onInterceptTouchEvent를 호출하여 이벤트를 가로 챌 것인지 여부를 결정합니다.
      • 가로 챈 경우 자체 onTouchEvent 메서드를 호출합니다.
      • 가로 채지 않은 경우 자식보기의 dispatchTouchEvent 메서드를 호출합니다.
    2. 자식 뷰가 이벤트를 사용하지 않으면 viewGroup 자체의 onTouchEvent가 호출됩니다.
    3. 위의 1 단계와 2 단계의 처리 결과는 viewGroup의 dispatchTouchEvent 메서드 처리 결과이며 상위 레이어의 onTouchEvent 처리로 반환됩니다.
  • 전망
    1. 뷰의 dispatchTouchEvent는 기본적으로 이벤트를 처리하기 위해 onTouchEvent를 호출하고, 소비 이벤트를 나타 내기 위해 true를 반환하고, 소비 이벤트가 없음을 나타 내기 위해 false를 반환합니다.
    2. 첫 번째 단계의 결과는 dispatchTouchEvent 메서드의 처리 결과입니다. 성공적으로 소비되면 true를 반환하고, 소비가 없으면 false를 반환하고 상위 레이어의 onTouchEvent에 제공합니다.

전체 워크 플로우가 "U"자형 구조임을 알 수 있으며, 가로 채지 않고 소비 이벤트보기는 레이어별로 검색됩니다. 그리고 현재 뷰가 이벤트를 처리하지 않으면 처리 된 viewGroup을 찾기 위해 레이어별로 처리됩니다.

위의 워크 플로 모델은 완전하지 않으며 고려되지 않은 다른 특수 상황이 있습니다. 몇 가지 특별한 경우가 아래에 설명되어 있습니다.

이벤트 순서가 중단됨

뷰가 다운 이벤트를 수신하면 터치 포인트의 다음 이벤트가 뷰에 의해 소비된다는 것을 알고 있습니다. 그러나 viewGroup은 중간에 이벤트 흐름을 중단 할 수 있습니다. 자식보기에 배포해야하는 모든 이벤트는 가로 채기 방법을 거쳐야하기 때문입니다. onInterceptTouchEvent(물론 자식보기에 대해 가로 채지 않음 플래그를 설정하는 경우 여기서는 설명하지 않습니다). 그렇다면 viewGroup이 이벤트 흐름을 방해 할 때 이벤트의 방향은 무엇입니까? 아래 그림을 참조하십시오. ( 여기에서는 다중 손가락 작업에 대해 설명하지 않으며 한 손가락 작업의 이동 또는 위로 이벤트 만 viewGroup에 의해 차단됩니다. )

  1. viewGroup이 자식보기의 이동 또는 위로 이벤트를 가로 채면 현재 이벤트를 취소 이벤트로 변경하고 자식보기로 보냅니다.
  2. 현재 이벤트 시퀀스가 ​​종료되지 않은 경우 다음 이벤트는 처리를 위해 viewGroup의 ouTouchEvent로 전달됩니다.
  3. 이때 viewGroup의 onTouchEvent 또는 view의 onTouchEvent가 false를 반환하는지 여부에 관계없이 전체 컨트롤 트리의 dispatchTouchEvent 메서드가 false를 반환합니다.
    • 이벤트 시퀀스는 하나의 뷰에서만 소비 될 수 있다는 원칙에 따라 뷰가 다운 이벤트를 소비하지만 다음 이동 또는 업 이벤트에서 false를 반환하면이 이벤트는 상위 viewGroup에서 처리되지 않고 직접 반환됩니다. 거짓.
멀티 터치 상황

위에서 설명한 모든 상황에는 멀티 터치 상황이 포함되지 않습니다. 멀티 터치의 경우 원본 이벤트 배포 과정에 몇 가지 특별한 경우가 추가되었습니다. 더 이상 여기에 그림을 그리지 않고 몇 가지 특별한 상황을 설명하면 독자가 이해할 수 있습니다.

기본적으로 viewGroup은 터치 사용 배포 지점이지만보기는 멀티 터치를 지원하지 않으므로 멀티 터치 dispatchTouchEvent를 지원 하려면 메서드를 재정의해야합니다 .

멀티 터치의 배포 규칙은 다음과 같습니다.

viewGroup이 다른 터치 포인트의 다운 이벤트를 수신하면 다른 손가락을 누르면 ACTION_POINTER_DOWN 이벤트가 생성되어 viewGroup에 전달됩니다.

  1. viewGroup은 ACTION_DOWN 방식으로 ACTION_POINTER_DOWN 이벤트를 배포합니다.
    • 하위보기가 이벤트를 사용하는 경우 단일 터치 프로세스와 일치합니다.
    • 하위보기가 이벤트를 사용하지 않으면 처리를 위해 다운 이벤트를 수신 한 마지막보기로 넘겨집니다.
  2. viewGroup의 두보기는 서로 다른 작동 중지 이벤트를 수신 한 다음보기 중 하나의 이벤트 시퀀스가 ​​차단되고 viewGroup은 차단 된 이벤트 시퀀스를 사용하지 않습니다. 즉, viewGroup과 해당 뷰는 동시에 터치 이벤트를 수신 할 수 없습니다.

활동 이벤트 배포

주의 깊은 독자는 위의 워크 플로가 활동을 포함하지 않는다는 것을 알게 될 것입니다. 우리의 인상에서 이벤트 분배는 모두 Activity -> Window -> ViewGroup, 그래서 무슨 일이 일어나고 있습니까? 이 모든 것이 DecorView의 "원인"입니다.

DecorView viewGroup dispatchTouchEvent은 터치 이벤트를 수신 한 후 메서드를 재정의하고 DecorView는 먼저 터치 개체 callBack 개체 내부로 전달됩니다. 맞습니다.이 콜백 객체는 Activity입니다. 활동 링크에 가입하면 배포 프로세스가 다음 그림에 표시됩니다.

전체적으로 이전 프로세스와 큰 차이는 없습니다. Activity는 Window.CallBack 인터페이스를 상속하므로 dispatchTouchEvent 및 onTouchEvent 메서드가 있습니다. 위의 그림을 간단하게 분석하십시오.

  1. 액티비티가 터치 이벤트를 수신하면 터치 이벤트를 viewGroup에 직접 배포합니다.
  2. viewGroup의 dispatchTouchEvent 메서드가 false를 반환하면 이벤트를 처리하기 위해 Activity의 onTouchEvent가 호출됩니다.
  3. 1 단계와 2 단계의 처리 결과는 활동의 dispatchTouchEvent 메서드 처리 결과이며 상위 계층으로 반환됩니다.

위의 프로세스는 Activity에 적용 할 수있을뿐만 아니라 DecorView 및 Dialog와 같은 콜백 모드를 사용하는 제어 시스템에도 적용 할 수 있습니다.

마침내

이 시점에서 이벤트 배포의 주요 내용도 설명합니다. 처음 두 기사를 결합하면 독자들이 이벤트 배포에 대해 더 높은 인식을 가지고 있다고 생각합니다.

그것은 항상 종이에 얕고 나는 그것을하는 방법을 절대적으로 알고 있습니다. 지식을 배우고 나서 가장 중요한 것은 연습입니다. 다음 기사에서는 학습 한 이벤트 배포 지식을 활용하는 방법을 간략히 분석하여 실제 개발에 적용 할 것입니다.

독창성은 쉽지 않습니다. 좋아하는 것이 제 창작의 가장 큰 동기입니다. 읽어 주셔서 감사합니다 ~

이것은 전체 텍스트입니다. 원본이 되기는 쉽지 않습니다. 도움이된다면 좋아요, 북마크, 댓글 달기, 전달할 수 있습니다.
저자는 매우 지식이 풍부하며 아이디어가 있으면 의견 섹션에서 자유롭게 의사 소통하고 수정하십시오.
재 인쇄가 필요한 경우에는 댓글 또는 비공개 메시지 교환을 부탁드립니다.

내 개인 블로그에 오신 것을 환영합니다 : Portal

추천

출처blog.csdn.net/weixin_43766753/article/details/113092505