안 드 로 이 드 의 Handler 비동기 통신 체 제 를 깊이 이해 하 다.

8141 단어 HandlerAndroid
1.문제:안 드 로 이 드 가 시 작 된 후에 새 프로 세 스에 메 인 스 레 드 를 만 들 것 입 니 다.UI 스 레 드(비 스 레 드 보안)라 고도 합 니 다.이 스 레 드 는 주로 화면 클릭 이벤트 와 인터페이스 그리 기 를 감청 합 니 다.애플 리 케 이 션 이 네트워크 요청 등 시간 이 걸 릴 때 메 인 스 레 드 에서 직접 진행 하면 ANR 오류 가 발생 하기 쉽다.그래서 서브 스 레 드 를 만들어 서 시간 이 걸 리 는 작업 을 수행 합 니 다.서브 스 레 드 가 완료 되면 UI 스 레 드 를 알 리 고 인터페이스 를 수정 해 야 할 때 서브 스 레 드 에서 UI 를 직접 수정 하면 안 됩 니 다.어떻게 합 니까?
해결 방법:Message Queue 메커니즘 은 하위 라인 과 UI 라인 의 통신 을 실현 할 수 있다.
이 메커니즘 은 Handler,Message Queue,Looper 를 포함한다.Handler 는 메시지/Runnable 대상 을 Looper 에 보 낼 수 있 습 니 다.이 메 시 지 를 소속 스 레 드 의 메시지 큐 에 넣 은 다음 Looper 는 메시지 큐 에 있 는 메시지/Runnable 대상 을 소속 스 레 드 에 있 는 Handler 로 자동 으로 방송 하고 받 은 메시지 나 Runnable 대상 을 Handler 에서 처리 합 니 다.
1、Handler
Handler 대상 을 만 들 때마다 생 성 된 스 레 드 에 자동 으로 연 결 됩 니 다.메 인 스 레 드 라면 기본적으로 Message Queue 를 포함 합 니 다.그렇지 않 으 면 메시지 큐 를 만들어 저장 해 야 합 니 다.
Handler 는 여러 스 레 드 통신 의 신사 이다.예 를 들 어 스 레 드 A 에서 A Handler 를 만 들 고 ALooper 를 연결 하 는 동시에 A 에 속 하 는 메시지 큐 AMessageQueue 를 만 듭 니 다.그리고 스 레 드 B 에서 A Handler 를 사용 하여 알 루 퍼 에 게 메 시 지 를 보 냅 니 다.알 루 퍼 는 메 시 지 를 AMessage Queue 에 저장 한 다음 에 A 스 레 드 에 있 는 A Handler 에 게 방송 합 니 다.메 시 지 를 받 으 면 처리 합 니 다.통신 을 실현 한다.
2、Message Queue
메 인 스 레 드 에 기본적으로 메시지 큐 가 포함 되 어 있 습 니 다.수 동 으로 만 들 필요 가 없습니다.하위 스 레 드 에 서 는 Looper.prepare()방법 을 사용 한 후 하위 스 레 드 에 looper 대상 이 있 는 지 확인 합 니 다.있 으 면 만 들 수 없습니다.스 레 드 마다 메시지 큐 만 있 기 때 문 입 니 다.없 으 면 하위 스 레 드 에 메시지 큐 를 만 듭 니 다.
3.handler 체 제 를 완전 하 게 만 듭 니 다.
Handler 클래스 는 Looper 지침 과 Message Queue 지침 을 포함 하고 Looper 에는 실제 Message Queue 와 현재 스 레 드 지침 이 포함 되 어 있 습 니 다.
다음은 UI 스 레 드 와 worker 스 레 드 에 대해 handler 생 성 과정 을 설명 합 니 다.
우선,handler 를 만 들 때 현재 스 레 드 에 looper 대상 이 포함 되 어 있 는 지 자동 으로 확인 합 니 다.포함 되 어 있 으 면 handler 내 메시지 대기 열 을 looper 내부 메시지 대기 열 로 가리 키 고 그렇지 않 으 면 이상 요청 을 던 져 looper.prepare()방법 을 실행 합 니 다.
 - UI 스 레 드 에서 시스템 은 자동 으로 Looper 대상 을 만 들 었 기 때문에 new handler 를 직접 사용 하면 이 메커니즘 을 사용 할 수 있 습 니 다.
-worker 스 레 드 에서 handler 를 직접 만 들 면 실행 중 이상 을 던 집 니 다.즉,'스 레 드-value'맵 표를 통 해 현재 스 레 드 에 looper 대상 이 없 음 을 발견 합 니 다.그래서 Looper.prepare()방법 을 먼저 호출 해 야 합 니 다.prepare 방법 에서 ThreadLocal대상 을 이용 하여 현재 스 레 드 에 Looper 를 만 듭 니 다(Values 클래스,즉 Map 맵 맵 표를 이용 하여 thread 에 value 를 저장 합 니 다.여 기 는 현재 thread 에 looper 대상 을 저장 합 니 다).그리고 handler 를 계속 만 들 고 handler 내부 의 메시지 큐 가 이 looper 의 메시지 큐 를 가리 키 도록 합 니 다.(이것 은 매우 중요 합 니 다.handler 가 looper 의 메시지 큐 를 가리 키 도록 합 니 다.즉,두 사람 이 같은 메시지 큐 를 공유 한 다음 handler 가 이 메시지 큐 에 메 시 지 를 보 냅 니 다.looper 는 이 메시지 큐 에서 메 시 지 를 가 져 옵 니 다)그리고 looper 순환 메시지 큐 를 사용 하면 됩 니 다.message 메 시 지 를 가 져 오 면 message 대상 의 target,즉 handler 를 원본 으로 보 내 handler 의 handle Message()방법 을 되 돌려 처리 합 니 다.
201638155156052.jpg (1240×930)
handler 메커니즘
4.핵심
 - handler 는 looper 와 메시지 큐 를 공유 하기 때문에 handler 가 메 시 지 를 보 내 면 열 에 들 어가 면 looper 는 직접 메 시 지 를 가 져 오 면 됩 니 다.
 - 스 레 드 와 looper 맵 표:하나의 스 레 드 는 looper 대상 을 최대 로 매 핑 할 수 있 습 니 다.현재 스 레 드 에 looper 가 포함 되 어 있 는 지 확인 할 수 있 습 니 다.포함 되 어 있 으 면 새 looper 를 만 들 지 않 습 니 다.
5.이러한 체 제 를 바탕 으로 어떻게 스 레 드 격 리 를 실현 합 니까?즉,스 레 드 에서 통신 합 니까?
핵심 은 모든 스 레 드 가 자신의 handler,message quue,looper 체 계 를 가지 고 있다 는 것 이다.각 스 레 드 의 핸들 러 는 공개 됐다.B 스 레 드 는 A 스 레 드 의 handler 를 호출 하여 A 의 공유 메시지 대기 열 로 메 시 지 를 보 낼 수 있 습 니 다.그리고 A 의 looper 는 자동 으로 공유 메시지 대기 열 에서 메 시 지 를 꺼 내 처리 합 니 다.반대로
201638155255976.jpg (960×720)
하위 스 레 드 가 주 스 레 드 에 메 시 지 를 보 냅 니 다.
201638155338002.jpg (960×720)
서브 스 레 드 간 통신
2.위 는 하위 스 레 드 에서 메 인 스 레 드 가 제공 하 는 Handler 를 이용 하여 메 시 지 를 보 낸 다음 에 메 인 스 레 드 의 Looper 가 메시지 대기 열 에서 가 져 와 처리 합 니 다.그러면 또 다른 두 가지 상황 이 있다.
1.메 인 스 레 드 에서 하위 스 레 드 로 메 시 지 를 보 냅 니 다.
채택 한 방법 은 앞 과 유사 하 다.하위 스 레 드 에서 AHandler 를 예화 하고 메 시 지 를 처리 하 는 방법 을 설정 해 야 합 니 다.또한 하위 스 레 드 에 메시지 큐 와 Looper 의 폴 링 이 없 기 때문에 Looper.prepare(),Looper.loop()을 추가 하여 각각 메시지 큐 를 만 들 고 폴 링 을 시작 해 야 합 니 다.그리고 메 인 스 레 드 에서 이 A Handler 를 사용 하여 메 시 지 를 보 내 면 됩 니 다.
2.서브 스 레 드 A 와 서브 스 레 드 B 간 의 통신.
3.Handler 안에 실 용적 인 API 가 있 습 니까?
기억 하 세 요:
Handler 는 단순히 메시지 큐 에 메 시 지 를 보 내 거나 post 방식 을 사용 합 니 다.
UI 스 레 드 와 통신 하 는 데 도움 이 되 는 더 편리 한 방법 이 있 습 니 다.
만약 당신 이 지금 Handler 의 API 를 본다 면,이 몇 가지 방법 을 똑똑히 볼 수 있 습 니 다.
  • post
  • postDelayed
  • postAtTime
  • 코드 예제
    이곳 의 코드 는 모두 매우 기본 적 인 것 이지 만,너 는 주석 을 잘 볼 수 있다.
    예시 1:Handler 의"post"방법 사용 하기
    
    public class TestActivity extends Activity {
     
    // ...
    // all standard stuff
     
    @Override
    public void onCreate(Bundle savedInstanceState) {
     
      
    // ...
      
    // all standard stuff
     
      
    // we're creating a new handler here
      
    // and we're in the UI Thread (default)
      
    // so this Handler is associated with the UI thread
      Handler mHandler = new Handler();
     
      
    // I want to start doing something really long
      
    // which means I should run the fella in another thread.
      
    // I do that by sending a message - in the form of another runnable object
     
      
    // But first, I'm going to create a Runnable object or a message for this
      Runnable mRunnableOnSeparateThread = new Runnable() {
        @Override
        public void run () {
     
          
    // do some long operation
          longOperation();
     
          
    // After mRunnableOnSeparateThread is done with it's job,
          
    // I need to tell the user that i'm done
          
    // which means I need to send a message back to the UI thread
     
          
    // who do we know that's associated with the UI thread?
          mHandler.post(new Runnable(){
            @Override
            public void run(){
              
    // do some UI related thing
              
    // like update a progress bar or TextView
              
    // ....
            }
          });
     
     
        }
      };
     
      
    // Cool but I've not executed the mRunnableOnSeparateThread yet
      
    // I've only defined the message to be sent
      
    // When I execute it though, I want it to be in a different thread
      
    // that was the whole point.
     
      new Thread(mRunnableOnSeparateThread).start();
    }
     
    }
    
    Handler 대상 이 아예 없다 면,post 방법 을 바 꾸 는 것 은 어 려 울 것 이다.
    예시 2:postDelayed 방법 사용 하기
    최근 에 본 사이트 에서 새로 소개 한 기능 에서 저 는 매번 EditText 의 자동 완성 기능 을 모 의 해 야 합 니 다.문자 가 바 뀔 때마다 API 호출 을 실행 하여 서버 에서 데 이 터 를 검색 합 니 다.
    앱 이 API 를 호출 하 는 횟수 를 줄 이 고 싶 어 Handler 의 postDelayed 방법 으로 이 기능 을 구현 하기 로 했다.
    이 예 는 평행 처 리 를 대상 으로 하지 않 고 Handler 가 메시지 대기 열 에 메 시 지 를 보 내 고 메 시 지 를 미래의 어느 한 지점 에서 실행 하도록 배정 하 는 등 이다.
    
    // the below code is inside a TextWatcher
    // which implements the onTextChanged method
    // I've simplified it to only highlight the parts we're
    // interested in
     
    private long lastChange = 0;
     
    @Override
    public void onTextChanged(final CharSequence chars,
                 int start, int before, int count) {
     
        
    // The handler is spawned from the UI thread
        new Handler().postDelayed(
     
          
    // argument 1 for postDelated = message to be sent
          new Runnable() {
            @Override
            public void run() {
     
              if (noChangeInText_InTheLastFewSeconds()) {
                searchAndPopulateListView(chars.toString()); 
    // logic
              }
            }
          },
     
          
    // argument 2 for postDelated = delay before execution
          300);
     
        lastChange = System.currentTimeMillis();
    }
     
     
    private boolean noChangeInText_InTheLastFewSeconds() {
      return System.currentTimeMillis() - lastChange >= 300
    }
    
    마지막 으로 저 는'post AtTime'이라는 방법 을 독자 들 에 게 연락 으로 남 겼 습 니 다.Handler 를 파악 하 셨 나 요?그렇다면 스 레 드 를 마음껏 사용 할 수 있 습 니 다.

    좋은 웹페이지 즐겨찾기