안 드 로 이 드 메시지 메커니즘 깊이 분석

Android 에서 스 레 드 내부 나 스 레 드 간 에 정보 교 류 를 할 때 정 보 를 자주 사용 합 니 다.이런 기본 적 인 것들 은 우리 가 내부 의 원 리 를 잘 알 면 시스템 을 쉽 고 잘 구축 하여 저급한 오 류 를 피 할 수 있 습 니 다.
모든 Android 응용 프로그램 은 시작 할 때 하나의 스 레 드 를 만 듭 니 다.이 스 레 드 는 주 스 레 드 나 UI 스 레 드 라 고 불 립 니 다.Android 응용 프로그램의 모든 작업 은 기본적으로 이 스 레 드 에서 실 행 됩 니 다.
그러나 데이터 요청,이미지 다운로드,또는 기타 시간 소모 작업 을 하려 면 이 UI 스 레 드 에서 할 수 없습니다.안 드 로 이 드 는 3.0 이후 버 전에 서 이 일 을 금지 하고 이상 을 직접 던 졌 기 때 문 입 니 다.그래서 UI 를 제외 한 작업 을 처리 하기 위해 서 는 하위 스 레 드 가 필요 합 니 다.
그러나 이것 은 또 하나의 문제 가 있 습 니 다.우 리 는 UI 스 레 드 프로 세 스 UI 에서 만 작업 할 수 있 습 니 다.하위 스 레 드 에서 만 시간 을 소모 할 수 있 습 니 다.만약 에 우리 가 시간 을 소모 하 는 작업 이 끝 난 후에 Android 인터페이스 에 View 를 표시 해 야 한다 면 우 리 는 어떻게 해 야 합 니까?우 리 는 하위 스 레 드 에서 UI 를 직접 새로 고 칠 수 없습니다.이 때 우 리 는 메 인 스 레 드 와 서브 스 레 드 의 통신 을 실현 하기 위해 안 드 로 이 드 메시지 체 제 를 사용 해 야 한다.쉽게 말 하면 서브 스 레 드 가 데 이 터 를 얻 은 후에 UI 업 데 이 트 를 직접 하지 않 고 데 이 터 를 메 인 스 레 드 에 저장 하여 메 인 스 레 드 로 보 내 는 것 입 니 다.메 인 스 레 드 에 순환 문의 가 있 으 면 바로 서브 스 레 드 에서 보 내 온 정 보 를 받 은 다음 에 메 시 지 를 받 은 후에 메 인 스 레 드 에서 UI 를 업데이트 합 니 다.말 하기는 비교적 간단 하 니,구체 적 으로 어떻게 말 하 는 지 자세히 보 자.
메 시 지 를 처리 하 는 수단-Handler,Looper,Message Queue
Handler
먼저 Handler 에 대해 설명 하 겠 습 니 다.Handler 는 말 그대로 처리 자 입 니 다.보통 그 에 대한 용법 은 UI 스 레 드 에 Handler 를 새로 만 들 고 그의 handle Message 를 복사 한 다음 에 시간 이 걸 리 는 스 레 드 에서 UI 스 레 드 에 메 시 지 를 포스트 합 니 다.예 는 다음 과 같 습 니 다.

class MyHandler extends Handler{
@Override
public void handleMessage(Message msg){
//  UI
}
}
MyHandler mHandler = new MyHandler();
new Thread(){
public void run(){
mHandler.sendEmptyMessage(123);
};
}.start(); 
UI 스 레 드 에서 만 Handler 가 기 존 Message Queue 와 연 결 될 수 있 도록 Handler 를 주 스 레 드 에 만들어 야 합 니 다.한편,Message Queue 는 Looper 에 봉인 되 었 고 Looper 는 Thread Local 을 통 해 하나의 스 레 드 에 봉인 되 었 으 며 마지막 으로 Message Queue 와 연 결 된 스 레 드 에 해당 합 니 다.그래서 쉽게 말 하면 Handler 가 스 레 드 와 연 결 된 Message Queue 에 메 시 지 를 보 낸 다음 Handler 가 Message Queue 에서 메 시 지 를 꺼 내 처리 하 는 것 이다.
Handler 가 자주 쓰 는 방법 2 가 지 를 볼 게 요.

void handleMessage(Message msg) :        
final boolean sendMessage(Message msg) :       
첫 번 째 방법 은 보통 UI 스 레 드 에서 실 행 됩 니 다.보통 UI 를 새로 고 치 는 데 사 용 됩 니 다.비정 상 내부 클래스 를 만 들 면 메모리 누 출 이 발생 할 수 있 습 니 다.이 블 로그 Handler 에서 발생 하 는 메모리 누 출 을 참고 하 십시오.두 번 째 방법 은 하위 스 레 드 에서 실 행 됩 니 다.Handler 의 정례 화 대상 이 필요 합 니 다.보통 메 인 스 레 드 에서 하위 스 레 드 에 전달 합 니 다.또한 메시지 대상 이 필요 합 니 다.msg.what 를 메시지 의 표시 로 지정 합 니 다.그러나 만약 에 우리 가 Handler 로 메 시 지 를 처리 할 때 post 방법 을 선택 하 는 것 이 더 좋 은 선택 입 니 다.예 는 다음 과 같 습 니 다.

private Handler mHandler = new Handler();
new Thread(new Runnable() {
@Override
public void run() {
mHandler.post(new Runnable() {
@Override
public void run() {
//UI  
...
}
});
}
}).start(); 
다음은 메시지 의 순환 대기 열 인 Message Queue 와 그 를 포장 하 는 Looper 순환 에 대해 토론 하 겠 습 니 다.
Looper 와 Message Queue
UI 스 레 드 에서 Handler 대상 을 만 들 고 예화 하 는 데 Looper 와 Message Queue 가 필요 없다 고 언급 했 습 니 다.왜냐하면 우리 의 응용 프로그램 은 시작 할 때 Activity ThreadMain 을 먼저 실 행 했 기 때 문 입 니 다.이 방법 은 자바 언어 가 실행 되 는 입구 Public 입 니 다.

static void main(String [] args)          MainLooper,       :
public static void main(string[] args){
//   
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if(sMainThreadHandler == null){
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
//   
Looper.loop();
} 
이 안 에는 Message Queue 가 나타 나 지 않 았 습 니 다.Looper 류 의 소스 코드 를 살 펴 보고 초기 화 할 때 어떤 재 미 있 는 일이 일 어 났 는 지 알 수 있 습 니 다.

public class Looper {
private static final ThreadLocal sThreadLocal = new ThreadLocal();
// Looper      
final MessageQueue mQueue;
//     
Thread mThread;
// 。。。    
//   Looper          ,       
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
//               TLS   Looper  
public static final void prepare() {
if (sThreadLocal.get() != null) {
//     Looper        Looper     
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
//     
} 
우리 한 줄 은 이 코드 를 볼 때 먼저 ThreadLocal 대상 을 예화 합 니 다.이것 은 Looper 순환 을 실현 하 는 현지 화 저장 소 입 니 다.ThreadLocal 은 이 글 이 왜 ThreadLocal 을 사용 하 는 지 볼 수 있 습 니 다.쉽게 말 하면 여러 스 레 드 가 Looper 대상 을 동시에 방문 할 때 우 리 는 synchronized 동기 화 체제 로 그 를 처리 하지 않 습 니 다.모든 스 레 드 에 자신의 Looper 던 전 을 만 드 는 것 입 니 다.A 스 레 드 는 A 의 looper 던 전 을 바 꾸 었 고 B 스 레 드 의 Looper 에 영향 을 주지 않 아 효율 적 인 스 레 드 안전 을 실현 합 니 다.뒤에 있 는 몇 마디 는 Message Queue 를 순서대로 정의 하고 Looper 를 사유 화 구 조 를 만 들 었 습 니 다.prepare 방법 에서 Looper 대상 을 sThreadLocal 에 설정 하 였 습 니 다.이렇게 Message Queue 는 Looper 대상 에 포장 하 는 동시에 ThreadLocal 을 통 해 스 레 드 와 Looper 를 연결 시 켜 메시지 대기 열 이 스 레 드 와 연결 되 고 서로 다른 스 레 드 는 상대방 의 메시지 대기 열 에 접근 할 수 없습니다.
다음 그림 에서 보 듯 이:

이어서 Looper.loop 순환 이 실 행 됩 니 다.loop 방법 에서 무슨 일이 일 어 났 는 지 살 펴 보 겠 습 니 다.

public static final void loop() {
Looper me = myLooper(); //      Looper
MessageQueue queue = me.mQueue; //    looper MQ
while (true) {
Message msg = queue.next(); //   message
if (msg != null) {
if (msg.target == null) {
return;
}
msg.target.dispatchMessage(msg);
msg.recycle();
}
}
}
이것 은 생략 판 코드 입 니 다.우 리 는 여기 서 무한 순환 실행 을 볼 수 있 습 니 다.먼저 메시지 대기 열 에서 메 시 지 를 계속 꺼 낸 다음 에 msg 가 비어 있 는 지,msg.target 이 비어 있 는 지,비어 있 지 않 으 면 dispatchMessage 방법 을 실행 합 니 다.이 방법 은 handler 의 한 방법 입 니 다.이 를 통 해 msg.target 이 handler 의 유형 임 을 알 수 있 습 니 다.이로써,Looper.prepare 와 Loop.loop 을 통 해 Message Queue,Looper,Handler 세 사람의 관 계 를 실현 했다.한편,Handler 는 Looper 와 Message Queue 와 연 결 된 것 은 Handler 의 기본 구조 기 에서 Looper.getLooper 를 통 해 loop 대상 을 가 져 와 Message Queue 를 가 져 옵 니 다.그 소스 코드 는 다음 과 같 습 니 다.

public Handler(){
//     looper MQ     MQ,            looper MQ 
mLooper = Looper.myLooper();
mQueue = mLooper.mQueue;
mCallback = null;
}
그리고 우리 의 흐름 도 는 다음 과 같이 많은 내용 을 담 을 수 있다.

dispatchMessage()방법 을 살 펴 보 겠 습 니 다.이 방법 은 실제 배포 방법 일 뿐 입 니 다.Runable 형식의 callback 이 비어 있 으 면 handlerMessage 를 실행 하여 메 시 지 를 처리 합 니 다.이 방법 은 비어 있 으 므 로 복사 해 야 합 니 다.비어 있 지 않 으 면 handle Callback 을 실행 합 니 다.실제로 handle 의 post 방법 을 사용 하면 callback 을 실 행 했 고 sendmessage 를 사용 하면 handleMessage 를 실 행 했 습 니 다.
이 곳 은 post(Runnable callback)든 handlerMessage 든 실제 적 으로 하나의 방법 으로 sendmessage Delayed(Message msg)를 호출 하고 있 습 니 다.handlerMessage 는 하나의 인 자 를 직접 받 아들 일 뿐 이 고 Runable callback 은 실제 적 으로 이 Runable 대상 을 Message 대상 의 callback 구성원 변 수 를 부여 하고 마지막 으로 Message 대상 을 메시지 대기 열 에 삽입 합 니 다.마지막 으로 Looper 는 Message Queue 에서 메 시 지 를 계속 읽 고 Handler 의 dispatchMessage 메 시 지 를 호출 하여 callback 이 비어 있 는 지 여부 에 따라 다른 방법 으로 실 행 됩 니 다.Android 메시지 메커니즘 분석 은 여기 서 마 치 겠 습 니 다.
처음
메 인 스 레 드 에서 Handler 대상 을 예화 해 야 UI 새로 고침 을 업데이트 할 수 있 는 이 유 를 알 게 되 었 습 니 다.UI 스 레 드 에 보 내 는 메시지 만 UI 스 레 드 의 handler 에 의 해 처리 되 기 때 문 입 니 다.만약 우리 가 비 UI 스 레 드 에서 Handler 를 예화 하려 면 먼저 스 레 드 를 LooperThread 로 바 꾸 고 예화 해 야 합 니 다.즉,다음 코드 를 실행 합 니 다.

Loop.prepare();
hander = new Handler;
Loop.loop
원인 에 대해 서 는 위의 설명 을 다 읽 으 면 알 것 이 라 고 믿 어야 한다.
이제 우리 의 첫 번 째 코드 를 살 펴 보고 마지막 으로 Handler 의 작업 절 차 를 뇌 보 자.

class MyHandler extends Handler{
@Override
public void handleMessage(Message msg){
//  UI
}
}
MyHandler mHandler = new MyHandler();
new Thread(){
public void run(){
mHandler.sendEmptyMessage(123);
};
}.start(); 
Handler 가 mHandler 로 실례 화 되 었 을 때 시스템 은 Handler 의 기본 구조 함 수 를 통 해 Handler 와 Looper 의 연결 을 완 성 했 고 Looper 를 통 해 Message Queue 에 연결 되 었 다.그리고 메 인 스 레 드 의 Looper 는 시스템 이 시 작 될 때 Loop.prepare 를 통 해 이미 구성 되 었 고 UI 스 레 드 와 Thread Local 을 통 해 연 결 된 다음 에 새로운 스 레 드 에서 mHandler.sendEmpty Message 를 실행 하여 Message Queue,Looper.loop 에 게 Message 를 보 냈 습 니 다.링 을 따라 갈 때 message 를 계속 꺼 내 Handler 에 게 처리 하고 우리 가 복사 한 HandleMessage 에서우리 가 보 낸 메 시 지 를 식별 하여 메 시 지 를 처리 합 니 다.물론 여 기 는 Empty 메시지 일 뿐 handle Message 에서 msg.what 의 판단 을 수행 하지 않 았 습 니 다.
이상 의 내용 은 편집장 이 여러분 에 게 소개 한 안 드 로 이 드 메시지 메커니즘 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다!

좋은 웹페이지 즐겨찾기