Androd 개발 예술 탐색 제10 장 안 드 로 이 드 메시지 메커니즘 독서 노트

8994 단어
선언: 안 드 로 이 드 메시지 메커니즘 을 잘 아 는 파트너 는 마지막 까지 메 인 라인 의 메시지 순환 을 볼 수 있 습 니 다.
Android 의 메시지 메커니즘 은 주로 Handler 의 운영 메커니즘 을 말 하 는데 Handler 의 운영 은 기본 Message Queue 와 Looper 의 기반 이 필요 합 니 다.Message Queue 는 메시지 목록 을 단일 체인 시트 의 데이터 구조 로 저장 합 니 다.Looper 는 새로운 메시지 가 있 는 지 없 는 지 를 무한 순환 으로 확인 하고 있 으 면 메 시 지 를 처리 합 니 다. 그렇지 않 으 면 계속 기 다 립 니 다.ThreadLocal 은 서로 다른 스 레 드 에서 서로 간섭 하지 않 고 데 이 터 를 저장 하고 제공 할 수 있 으 며 ThreadLocal 을 통 해 모든 스 레 드 의 Looper 를 쉽게 얻 을 수 있 습 니 다.
10.1 Android 메시지 메커니즘 개요
  • Handler 의 주요 역할 은 특정한 임 무 를 Handler 가 있 는 스 레 드 로 전환 하여 수행 하 는 것 이다.왜 안 드 로 이 드 가 이 기능 을 제공 합 니까?이 는 Android 가 UI 에 접근 할 때 주 스 레 드 만 통과 할 수 있 도록 규정 하고 있 기 때 문 입 니 다. 하위 스 레 드 가 UI 에 접근 하면 프로그램 에 이상 이 발생 합 니 다.ViewRootImpl 은 checkThread 방법 에서 판단 을 내 렸 다.
  • Android 가 메 인 스 레 드 에서 시간 소모 작업 을 권장 하지 않 기 때문에 그렇지 않 으 면 ANR 로 이 어 질 수 있 습 니 다.그러면 우 리 는 서브 스 레 드 가 실 행 된 후에 UI 를 업데이트 하 는 작업 을 메 인 스 레 드 로 전환 해 야 합 니 다.그래서 시스템 이 Handler 를 제 공 했 습 니 다.
  • 시스템 은 왜 하위 스 레 드 에서 UI 에 접근 하 는 것 을 허락 하지 않 습 니까?Android 의 UI 컨트롤 은 스 레 드 가 안전 하지 않 기 때문에 다 중 스 레 드 동시 방문 은 UI 컨트롤 이 예상 치 못 한 상태 에 있 을 수 있 습 니 다. 왜 잠 금 을 추가 하지 않 습 니까?잠 금 메커니즘 은 UI 접근 논 리 를 복잡 하 게 만 들 기 때문이다.그 다음 에 잠 금 메커니즘 은 UI 접근 의 효율 을 낮 출 수 있 습 니 다. 잠 금 메커니즘 이 일부 스 레 드 의 실행 을 막 을 수 있 기 때 문 입 니 다.그래서 Android 는 효율 적 인 단일 스 레 드 모델 로 UI 작업 을 처리 합 니 다.
  • Handler 생 성 시 현재 스 레 드 의 Looper 를 사용 하여 내부 메시지 순환 시스템 을 구축 합 니 다. 현재 스 레 드 에 Looper 가 없 으 면 오류 가 발생 합 니 다.Handler 는 post 방법 으로 Runnable 을 메시지 대기 열 에 보 낼 수도 있 고 send 방법 으로 메시지 대기 열 에 메 시 지 를 보 낼 수도 있 습 니 다. 사실 post 방법 도 결국 send 방법 으로 이 루어 집 니 다.
  • Message Queue 의 enqueue Message 방법 은 최종 적 으로 이 메 시 지 를 메시지 대기 열 에 넣 습 니 다. Looper 가 새로운 메시지 가 온 것 을 발견 하면 이 메 시 지 를 처리 합 니 다. 최종 메시지 의 Runnable 이나 Handler 의 handle Message 방법 이 호출 됩 니 다. Looper 는 Handler 가 있 는 스 레 드 를 실행 하 는 것 입 니 다.이렇게 되면 업무 논 리 는 Handler 가 있 는 스 레 드 로 전환 되 어 실 행 됩 니 다.

  • 10.2 Android 의 메시지 메커니즘 분석
    10.2.1 ThreadLocal 의 작업 원리
  • ThreadLocal 은 스 레 드 내부 의 데이터 저장 류 로 지정 한 스 레 드 에 데 이 터 를 저장 할 수 있 습 니 다. 데 이 터 를 저장 한 후에 지정 한 스 레 드 에서 만 저 장 된 데 이 터 를 얻 을 수 있 고 다른 스 레 드 에 대해 서 는 데 이 터 를 얻 을 수 없습니다.일반적으로 데이터 가 스 레 드 를 역할 영역 으로 하고 스 레 드 에 따라 복사 본 이 다 를 때 ThreadLocal 을 사용 하 는 것 을 고려 할 수 있 습 니 다.Handler 의 경우 현재 스 레 드 의 Looper 를 가 져 와 야 합 니 다. Looper 의 역할 은 스 레 드 이 고 서로 다른 스 레 드 가 서로 다른 Looper 를 가지 기 때문에 ThreadLocal 을 통 해 스 레 드 의 접근 을 쉽게 실현 할 수 있 습 니 다.
  • ThreadLocal 의 또 다른 사용 장면 은 복잡 한 논리 에서 의 대상 전달 이다.
  • ThreadLocal 원리: 서로 다른 스 레 드 가 같은 ThreadLoacl 의 get 방법 에 접근 합 니 다. ThreadLocal 의 get 방법 은 각자 의 스 레 드 에서 하나의 배열 을 꺼 낸 다음 배열 에서 현재 ThreadLocal 의 색인 에 따라 해당 하 는 Value 값 을 찾 습 니 다.(1) ThreadLocal set 방법 / / PS: JDK 에서 Android SDK 의 ThreadLocal 과 약간의 차이 가 있 습 니 다. SDK 의 경우
  •     public void set(T value) {
            Thread currentThread = Thread.currentThread();
            Values values = values(currentThread);
            if (values == null) {
                values = initializeValues(currentThread);
            }
            values.put(this, value);
        }
    

    현재 스 레 드 를 가 져 오고 현재 스 레 드 에서 해당 하 는 ThreadLocalMap (내 부 는 Entry [] table 로 ThreadLoacl 의 값 을 저장 합 니 다) 을 꺼 내 서 해당 데 이 터 를 저장 합 니 다.ThreadLocalMap 이 비어 있 으 면 이 스 레 드 의 ThreadLocalMap 대상 을 만 들 고 ThreadLocal 의 값 을 저장 합 니 다.(2) ThreadLocal get 방법
        public T get() {
            // Optimized for the fast path.
            Thread currentThread = Thread.currentThread();
            Values values = values(currentThread);
            if (values != null) {
                Object[] table = values.table;
                int index = hash & values.mask;
                if (this.reference == table[index]) {
                    return (T) table[index + 1];
                }
            } else {
                values = initializeValues(currentThread);
            }
            return (T) values.getAfterMiss(this);
        }
    

    현재 스 레 드 를 가 져 오고 현재 스 레 드 에서 해당 하 는 ThreadLocalMap 을 가 져 오 며 key 를 통 해 해당 하 는 value 를 가 져 옵 니 다.해당 하 는 ThreadLocalMap 을 가 져 오지 않 으 면 대상 을 만 들 고 되 돌려 줍 니 다.(3) ThreadLocal 의 값 이 table 수치 에 있 는 위 치 는 항상 ThreadLocal 의 색인 + 1 입 니 다.
    10.2.2 메시지 큐 의 작업 원리
  • Message Queue 는 주로 두 가지 조작 이 있 는데 삽입 과 읽 기, 읽 기 동작 은 삭제 작업 과 수반 된다.Message Queue 는 단일 링크 의 데이터 구 조 를 통 해 메시지 목록 을 유지 합 니 다.
  • enqueueMessage 방법의 역할 은 메시지 대기 열 에 메 시 지 를 삽입 하 는 것 입 니 다.next 방법 은 무선 순환 방법 입 니 다. 메시지 대기 열 에 메시지 가 없 으 면 next 방법 은 계속 막 힙 니 다.새로운 메시지 가 도착 하면 next 방법 은 이 메 시 지 를 되 돌려 주 고 단일 링크 에서 제거 합 니 다.

  • 10.2.3 Looper 의 작업 원리
  • prepareMainLooper 방법 은 주로 메 인 스 레 드, 즉 Activity Thread 에 Looper 를 만 드 는 데 사용 되 고 본질 도 prepare 방법 을 통 해 이 루어 진다.
  • Looper 는 quit 와 quit Safely 를 제공 하여 Looper 를 종료 합 니 다. quit 는 Looper 를 직접 종료 하고 quit Safely 는 메시지 대기 열 에 있 는 정 보 를 처리 한 후에 야 안전하게 종료 합 니 다.로 퍼 가 탈퇴 하면 이때 핸들 러 를 통 해 보 낸 메시지 가 실패 하고, 핸들 러 의 send 방법 은 false 로 되 돌아 갑 니 다.하위 스 레 드 에서 수 동 으로 Looper 를 만 들 면 모든 일이 끝 난 후에 Looper 의 quit 방법 으로 메시지 순환 을 중지 해 야 합 니 다. 그렇지 않 으 면 이 하위 스 레 드 는 계속 대기 상태 에 있 을 것 입 니 다.Looper 를 종료 하면 이 스 레 드 는 즉시 종 료 됩 니 다. 따라서 필요 하지 않 을 때 Looper 를 종료 하 는 것 을 권장 합 니 다.
  • loop 방법 은 Message Queue 의 next 방법 으로 새로운 정 보 를 얻 을 수 있 습 니 다. next 는 차단 작업 이지 만 정보 가 없 을 때 next 방법 은 계속 막 혀 있 습 니 다. 이것 은 loop 방법 이 계속 막 혀 있 습 니 다.Message Queue 의 next 방법 이 새로운 메 시 지 를 되 돌려 주면 Looper 는 이 메 시 지 를 처리 합 니 다. mas. target. dispatchMessage (msg), 여기 msg. target 은 이 메 시 지 를 보 낸 Handler 대상 입 니 다. 그러면 Handler 가 보 낸 메 시 지 는 결국 Handler 에 게 전 달 됩 니 다.

  • 10.2.4 Handler 의 작업 원리
  • Handler 의 작업 은 주로 메시지 의 발송 과 수용 과정 을 포함한다.전송 과정 은 post 의 일련의 방법 과 send 의 일련의 방법 을 통 해 이 루어 집 니 다.Handler 전송 과정 은 메시지 대기 열 에 메시지 하나만 삽입 되 었 습 니 다.Message Queue 의 next 방법 은 이 메 시 지 를 Looper 에 게 되 돌려 주 고 Looper 는 이 메 시 지 를 받 으 면 처 리 를 시작 하 며 최종 메 시 지 는 Handler 에 게 맡 깁 니 다.
  • Handler 처리 정보
  •     public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
                //Message callback   Runnable,       
               //   Handler  post      Runnable  
                handleCallback(msg);
            } else {
                //   Handler   Callback   ,
                //   Callback handleMessage(msg)
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                //  Handler handleMessage       ,
                // Handler     handlerMessage(msg)  
                handleMessage(msg);
            }
        }
        private static void handleCallback(Message message) {
            message.callback.run();
        }
        public interface Callback {
            public boolean handleMessage(Message msg);
        }
        //     
        public void handleMessage(Message msg) {
        }
    
  • Handler 는 또 하나의 특수 한 구조 방법 이 있 는데 특수 한 Looper 를 지정 하여 Handler 를 구성 할 수 있다.
  •     public Handler(Looper looper) {
            this(looper, null, false);
        }
    
  • Handler 생 성 은 Looper 가 필요 합 니 다. 그렇지 않 으 면 이상 이 발생 합 니 다. 기본적으로 현재 스 레 드 의 Looper 를 가 져 옵 니 다.주 스 레 드 즉 Activity Thread 는 자동 으로 Looper 를 만 들 고 다른 스 레 드 는 Looper 가 필요 하 다 면 수 동 으로 만들어 야 합 니 다.

  • 10.3 메 인 스 레 드 메시지 순환
  • Android 의 메 인 스 레 드 는 Activity Thread 입 니 다. 메 인 스 레 드 의 입구 방법 은 main 입 니 다. main 방법 에서 시스템 은 Looper. prepareMainLooper () 를 통 해 메 인 스 레 드 의 Looper 와 Message Queue 를 만 들 고 Looper. loop () 을 통 해 메 인 스 레 드 의 메시지 링 을 엽 니 다.
  • public static void main(String[] args) {
            ... 
            Process.setArgV0("");
     
            Looper.prepareMainLooper();
     
            ActivityThread thread = new ActivityThread();
            thread.attach(false);
     
            if (sMainThreadHandler == null) {
                sMainThreadHandler = thread.getHandler();
            }
    
            AsyncTask.init();
    
            if (false) {
                Looper.myLooper().setMessageLogging(new
                        LogPrinter(Log.DEBUG, "ActivityThread"));
            }
    
            Looper.loop();
    
            throw new RuntimeException("Main thread loop unexpectedly exited");
    }
    
  • Looper. loop () 은 주 스 레 드 의 Looper 가 종료 되면 프로그램 에 이상 이 발생 합 니 다.그러면 문제 가 생 겼 습 니 다. 메 인 라인 이 여기에 걸 렸 으 니 (1) Activity 가 왜 작 동 할 수 있 습 니까?(2) 단 추 를 눌 러 도 응답 할 수 있 습 니까?문제 1: startActivity 는 AMS (Activity Manager Service) 에 크로스 프로 세 스 요청 (AMS 가 시스템 프로 세 스 에서 실 행 됨) 을 보 내 고 AMS 가 해당 하 는 Activity 를 시작 합 니 다.AMS 도 App 에 있 는 Activity 의 라 이 프 사이클 방법 (프로 세 스 별로 직접 호출 할 수 없 음) 을 호출 해 야 합 니 다. AMS 는 크로스 프로 세 스 요청 을 보 낸 다음 App 의 Activity Thread 에 있 는 ApplicationThread 에서 처리 합 니 다. ApplicationThread 는 메 인 스 레 드 의 Handler 를 통 해 실행 논 리 를 메 인 스 레 드 로 전환 합 니 다.중요 한 것 은 메 인 스 레 드 의 Handler 가 message Queue 에 메 시 지 를 추 가 했 습 니 다. Looper. loop 은 이 메 시 지 를 받 고 메 인 스 레 드 에서 실 행 됩 니 다.이것 은 메 인 스 레 드 의 Looper 가 죽은 순환 이 고 Activity 가 시작 할 수 있 는 이 유 를 설명 한다. 4 대 구성 요소 의 생명 주 기 는 모두 UI 스 레 드 의 Handler 를 통 해 메시지 로 보 내 고 UI 스 레 드 의 Looper 에서 실행 되 기 때문이다.문제 2: 문제 1 원리 와 마찬가지 로 최종 적 으로 시스템 에서 메 시 지 를 보 내 처리 되 었 고 모두 Looper. loop () 을 거 쳤 다.문제 2 상세 분석 은 원서 작성 자의 Android 에서 MotionEvent 의 출처 와 ViewRootImpl
  • 을 보십시오.
    나 에 대해 서
    :HuDP WeChat:mox1103 WeiBo:HuDP_ 어서 오 세 요, 여러분. 댓 글 소통. [신 나 는 얼굴]

    좋은 웹페이지 즐겨찾기