Android 비동기 메시지 메커니즘 상세 설명

Android 의 비동기 메시지 체 제 는 Message,Handler,Message Queue 와 Looper 로 나 뉜 다.
그 중에서 Message 는 라인 간 에 전 달 된 메시지 로 what,arg 1,arg 2 필드 는 정형 데 이 터 를 휴대 할 수 있 고 obj 필드 는 Object 대상 을 휴대 할 수 있다.
Handler 는 메 시 지 를 보 내 고 처리 하 는 데 주로 사용 되 는 처리 자 입 니 다.메 시 지 를 보 내 는 방법 은 sendmessage 입 니 다.메 시 지 를 처리 하 는 방법 은 handleMessage()이 며,Message 필드 에 지 니 고 있 는 정 보 는 이 방법 에서 판별 합 니 다.
Message Queue 는 모든 Handler 가 보 낸 메 시 지 를 저장 하 는 메시지 큐 입 니 다.
Looper 는 메시지 큐 의'관리자'로 메시지 큐 에서 메 시 지 를 하나씩 꺼 내 Handler 의 handle Message()방법 에 할당 합 니 다.
비동기 메시지 처리 프로 세 스:

① 우선 메 인 스 레 드 에 Handler 대상 을 만 들 고 handleMessage()방법 을 다시 써 야 한다.
② 하위 스 레 드 가 처리 되 는 데 걸 리 는 시간 이 걸 릴 때 처리 결 과 를 UI 에 피드백 해 야 할 때 message 대상 을 만 들 고 what 필드 에 int 값 을 가지 고 Handler 대상 을 통 해 보 냅 니 다.
③ 이후 이 메 시 지 는 Message Queue 에 추가 되 어 처 리 를 기다 리 고 있 으 며,Looper 는 Message Queue 에서 처리 할 메 시 지 를 꺼 내 서 Handler 대상 의 handle Message()방법 으로 보 내 려 고 시도 하고 있다.Handler 대상 은 메 인 스 레 드 에서 만 들 어 졌 기 때문에 handleMessage()방법 에서 안심 하고 UI 작업 을 할 수 있 습 니 다.
하나의 예 를 통 해 확인 해 보 겠 습 니 다.이벤트 MainActivity 에는 단추 와 TextView 가 있 습 니 다.TextView 는"Hello World!"를 초기 화 합 니 다.이후 버튼 을 눌 러 시간 소모 조작 하기;시간 소모 작업 이 끝나 면 TextView 에'Nice to meet you'가 표 시 됩 니 다.이상 의 분석 에 근거 하여 나 는 비 할 바 없 이 자 연 스 럽 게 다음 과 같은 코드 를 썼 다.

package com.shaking.androidthreadtest;

import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
 private static final int UPDATE_TEXT=1;
 private String data;
 private TextView textView;
 
 private Handler handler=new Handler(){
 @Override
 public void handleMessage(Message msg) {
  switch (msg.what){
  case UPDATE_TEXT:
   textView.setText(data);
  }
 }
 };

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main_layout);
 Button button=findViewById(R.id.button);
 textView=findViewById(R.id.text_view);
 button.setOnClickListener(this);
 }

 @Override
 public void onClick(View view) {
 new Thread(new Runnable() {
  @Override
  public void run() {
  //           ,         data
  data="Nice to meet you";
  Message message=new Message();
  message.what=UPDATE_TEXT;
  handler.sendMessage(message);
  }
 }).start();
 }
}

우선,이렇게 쓰 는 것 은 틀림없이 잘못 이 없 을 것 이다!프로그램 도 정상적으로 작 동 할 수 있다.그러나 IDE 는"This Handler class should be static or leaks might occur"라 고 경고 했다.
이 경 고 는 우리 가 Handler 라 는 종 류 를 사용 할 때 정적 으로 밝 혀 야 한 다 는 뜻 이다.그렇지 않 으 면 메모리 가 새 어 나 갈 수 있다.
그렇다면 왜 메모리 유출 이 일 어 났 을 까?원인 은:
첫째:Handler 대상 의 sendmessage()방법 으로 Message 대상 을 보 낼 때 이 Message 대상 은 이 Handler 대상 에 대한 인용 을 가지 고 있 습 니 다(바로 이 인용 에 의 해 Looper 가 메시지 대기 열 에서 이 Message 대상 을 꺼 낸 후에 야 이 Message 대상 을 정확하게 이 Handler 대상 으로 나 눌 수 있 습 니 다!).
둘째,주 스 레 드 에서 Handler 대상 을 만 들 때 handleMessage()방법 을 다시 쓰기 위해 익명 내부 클래스 를 사용 하여 Handler 대상 을 만 들 었 습 니 다.익명 내부 클래스 와 비정 상 내부 클래스 는 모두 외부 클래스 에 대한 인용 을 은연 중 에 가지 고 있 습 니 다!따라서 이 Handler 대상 은 외부 클래스 인 MainActivity 의 인용 을 가지 고 있다.
상기 두 가 지 를 결합 하면 문제 가 생 긴 다.Message 대상 은 Handler 대상 인용 을 가지 고 있 고 Handler 대상 은 MainActivity 의 인용 을 가지 고 있다.그래서 MainActivity 이 활동 은 메시지 가 회수 될 때 까지 메모리 에서 회수 할 수 없습니다!Message 대상 이 하위 스 레 드 에서 메시지 대기 열 로 전송 되 고 처리 되 지 않 으 면 메모리 에서 회수 되 지 않 고 메 인 스 레 드 가 계속 걸 려 있 습 니 다.그래서 메모리 유출 로 이 어 질 수 있다.
이 유 를 알 았 다 면 해결 방법 은 무엇 입 니까?사실 이전의 경 고 는 이미 해결 방안 을 제시 했다.정적 내부 클래스 를 통 해 Handler 대상 을 만 드 는 것 입 니 다.정적 내부 클래스 는 외부 클래스 의 인용 을 가지 지 않 기 때 문 입 니 다.
이때,나 는 자 연 스 럽 게 정적 내부 클래스 를 만 들 고 Handler 클래스 를 계승 한 다음 에 handleMessage 방법 을 다시 쓴다.

private static class MyHandler extends Handler{
 @Override
 public void handleMessage(Message msg) {
   
  
 }
 }


그런데 여기 또 문제 가 생 겼 어 요!만약 내 가 외부 류 에 대한 인용 을 가지 고 있 지 않다 면,나 는 어떻게 외부 류 의 방법 과 대상 을 사용 합 니까?handle Message()방법 에서 UI 작업 을 해 야 하 니까 요.
정적 내부 클래스 를 사용 하여 메모리 유출 을 피하 고 외부 클래스 를 호출 하 는 방법 이 필요 한 경우:약 한 인용 을 사용 할 수 있 습 니 다!즉,우 리 는 이 내부 류 에서 대외 부 대상 의 약 한 인용 을 성명 하 는 것 이다.이렇게 하면 외부 클래스 를 호출 할 수 있 고 메모리 유출 을 초래 하지 않 을 것 이다.
구체 적 으로 수 정 된 코드 는 다음 과 같다.

package com.shaking.androidthreadtest;

import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.lang.ref.WeakReference;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
 private static final int UPDATE_TEXT=1;
 private String data;
 private TextView textView;

 private static class MyHandler extends Handler{
 //               
 private WeakReference<MainActivity> weakReference;
 //            
 MyHandler(MainActivity activity){
  weakReference=new WeakReference<>(activity);
 }
 @Override
 public void handleMessage(Message msg) {
  //      get()            
  MainActivity activity=weakReference.get();
  activity.textView.setText(activity.data);
 }
 }
 //  Handler  
 private MyHandler handler=new MyHandler(this);
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main_layout);
 Button button=findViewById(R.id.button);
 textView=findViewById(R.id.text_view);
 button.setOnClickListener(this);
 }

 @Override
 public void onClick(View view) {
 new Thread(new Runnable() {
  @Override
  public void run() {
  //           ,         data
  data="Nice to meet you";
  Message message=new Message();
  message.what=UPDATE_TEXT;
  handler.sendMessage(message);
  }
 }).start();
 }
}
이상 의 모든 문 제 를 완벽 하 게 해결 하 세 요!6~
마지막 으로 마지막 해결 방안 을 직접 사용 하 는 것 을 추천 합 니 다:정적 내부 클래스+약 참조.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기