Android Handler 다 중 스 레 드 상세 설명

Android--다 중 스 레 드 Handler
머리말
Android 의 메시지 전달 메커니즘 은 또 다른 형식의'이벤트 처리'입 니 다.이 메커니즘 은 주로 Android 응용 프로그램의 다 중 스 레 드 문 제 를 해결 하기 위해 서 입 니 다.Android 에 서 는 Activity 가 새로 시작 하 는 스 레 드 가 이 Activity 의 UI 구성 요소 에 접근 하 는 것 을 허용 하지 않 습 니 다.그러면 새로 시작 하 는 스 레 드 가 UI 구성 요소 의 속성 값 을 변경 할 수 없습니다.그러나 실제 개발 에서 많은 부분 에서 작업 라인 에서 UI 구성 요소 의 속성 값 을 바 꿔 야 한다.예 를 들 어 네트워크 이미지 다운로드,애니메이션 다운로드 등 이다.이 블 로 그 는 주로 Handler 가 스 레 드 에 올 라 온 메 시 지 를 어떻게 보 내 고 처리 하 는 지 를 소개 하고 Message 의 몇 가지 데 이 터 를 전달 하 는 방식 을 설명 하 며 마지막 으로 모두 작은 데모 로 시연 한다.
Handler
Handler 는 Object 에서 직접 계승 합 니 다.Handler 는 Message 나 Runnable 대상 을 보 내 고 처리 할 수 있 으 며 메 인 스 레 드 의 Message Queue 에 연 결 됩 니 다.각각 Handler 는 하나의 단독 스 레 드 를 가지 고 있 으 며 하나의 메시지 큐 에 연 결 된 스 레 드 를 가지 고 있 습 니 다.즉,Handler 는 고유 한 메시지 큐 를 가지 고 있 습 니 다.Handler 를 예화 할 때 하나의 스 레 드 와 메시지 큐 의 스 레 드 에 실 을 수 있 습 니 다.이 Handler 는 Message 나 Runnable 을 메시지 큐 에 누 르 고 메시지 큐 에서 Message 나 Runnable 을 꺼 내 서 조작 할 수 있 습 니 다.
Handler 는 주로 두 가지 역할 을 합 니 다.
작업 스 레 드 에서 메 시 지 를 보 냅 니 다.
UI 스 레 드 에서 정 보 를 가 져 오고 처리 합 니 다.
Handler 는 메시지 대상 이나 Runnable 대상 을 메시지 대기 열 에 눌 러 서 UI 스 레 드 에서 Message 를 가 져 오 거나 Runnable 대상 을 실행 할 수 있 기 때문에 Handler 는 메시지 대기 열 에 눌 러 두 가지 시스템 이 있 습 니 다.Post 와 sendmessage:
Post:Post 는 Runnable 대상 을 메시지 대기 열 에 넣 을 수 있 도록 합 니 다.그것 의 방법 은 post(Runnable),postAtTime(Runnable,long),postDelayed(Runnable,long)가 있다.
sendmessage:sendmessage 는 메시지 데 이 터 를 포함 하 는 Message 대상 을 메시지 대기 열 에 누 를 수 있 습 니 다.이 방법 은 sendEmpty Message(int),sendmessage(Message),sendmessage AtTime(Message,long),sendmessage Delayed(Message,long)가 있 습 니 다.
위의 여러 가지 방법 을 통 해 알 수 있 듯 이 post 든 sendmessage 든 모두 여러 가지 방법 을 가지 고 있 습 니 다.Runnable 대상 과 Message 대상 이 메시지 대기 열 에 들 어가 면 즉시 실행 하거나 지연 시 킬 수 있 습 니 다.
Post
Handler 의 Post 방식 에 있어 서 Runnable 대상 을 메시지 대기 열 에 전달 합 니 다.이 Runnable 대상 에서 run()방법 을 다시 씁 니 다.일반적으로 이 run()방법 에 UI 스 레 드 에 필요 한 동작 을 기록 합 니 다.
Handler 에서 Post 방식 에 대한 방법 은 다음 과 같 습 니 다.
boolean post(Runnable r):Runnable 하 나 를 메시지 대기 열 에 넣 고 UI 스 레 드 를 메시지 대기 열 에서 이 대상 을 꺼 낸 후 즉시 실행 합 니 다.
boolean postAtTime(Runnable r,long uptime Millis):Runnable 을 메시지 대기 열 에 넣 고 UI 스 레 드 를 메시지 대기 열 에서 이 대상 을 꺼 낸 후 특정한 시간 에 실행 합 니 다.
boolean postDelayed(Runnable r,long delay Millis):Runnable 하 나 를 메시지 대기 열 에 넣 고 UI 스 레 드 를 메시지 대기 열 에서 이 대상 을 꺼 낸 후 delay Mills 초 지연 실행
void removeCallbacks(Runnable r):메시지 대기 열 에서 Runnable 대상 을 제거 합 니 다. 
다음은 Demo 를 통 해 Handler 의 post 방식 으로 새로 시작 하 는 스 레 드 에서 UI 구성 요소 의 속성 을 수정 하 는 방법 을 설명 합 니 다.

package com.bgxt.datatimepickerdemo;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class HandlerPostActivity1 extends Activity {
 private Button btnMes1,btnMes2;
 private TextView tvMessage;
 //     Handler  
 private static Handler handler=new Handler();
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.message_activity); 
 
 btnMes1=(Button)findViewById(R.id.btnMes1);
 btnMes2=(Button)findViewById(R.id.btnMes2);
 tvMessage=(TextView)findViewById(R.id.tvMessage);
 btnMes1.setOnClickListener(new View.OnClickListener() {
  
  @Override
  public void onClick(View v) {
  //         
  new Thread(new Runnable() {   
   @Override
   public void run() {
   // tvMessage.setText("...");
   //        ,         UI  ,UI        UI     
   //   post    UI  tvMessage Text  
   handler.post(new Runnable() {   
    @Override
    public void run() {
    tvMessage.setText("  Handler.post                  ,       。");   
    }
   });    
   }
  }).start();
  }
 });
 
 btnMes2.setOnClickListener(new View.OnClickListener() {
  
  @Override
  public void onClick(View v) {
  new Thread(new Runnable() {   
   @Override
   public void run() {
   //   postDelayed    UI  tvMessage Text   
   //     3S  
   handler.postDelayed(new Runnable() {
    
    @Override
    public void run() {
    tvMessage.setText("  Handler.postDelayed                  ,       3S  。"); 
    
    }
   }, 3000);   
   }
  }).start();
  
  }
 });
 }
}
효과 표시:

한 가지 주의해 야 할 것 은 Post 방식 에 있어 서 Runnable 대상 의 run()방법 코드 는 모두 UI 스 레 드 에서 실 행 됩 니 다.따라서 이 코드 에 있어 서 UI 스 레 드 에서 의 작업 을 수행 할 수 없고 post 방식 으로 실 행 될 수 없습니다.예 를 들 어 네트워크 를 방문 하면 다음 과 같은 예 를 들 어 post 방식 으로 인터넷 에서 그림 을 가 져 옵 니 다.이미지 뷰 에 표 시 됩 니 다.

package com.bgxt.datatimepickerdemo;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

public class HandlerPostActivity2 extends Activity {
 private Button btnDown;
 private ImageView ivImage;
 private static String image_path = "http://ww4.sinaimg.cn/bmiddle/786013a5jw1e7akotp4bcj20c80i3aao.jpg";
 private ProgressDialog dialog;
 //      Handler,Handler        
 private static Handler handler=new Handler();
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.asynctask_activity);
 
 btnDown = (Button) findViewById(R.id.btnDown);
 ivImage = (ImageView) findViewById(R.id.ivSinaImage);

 dialog = new ProgressDialog(this);
 dialog.setTitle("  ");
 dialog.setMessage("    ,   ...");
 dialog.setCancelable(false);
 
 btnDown.setOnClickListener(new View.OnClickListener() {  
  @Override
  public void onClick(View v) {
  //        ,      
  new Thread(new MyThread()).start();
  //      
  dialog.show();
  }
 });
 }
 
 public class MyThread implements Runnable {

 @Override
 public void run() {
  //       
  HttpClient httpClient = new DefaultHttpClient();
  HttpGet httpGet = new HttpGet(image_path);
  HttpResponse httpResponse = null;
  try {
  httpResponse = httpClient.execute(httpGet);
  if (httpResponse.getStatusLine().getStatusCode() == 200) {
   byte[] data = EntityUtils.toByteArray(httpResponse
    .getEntity());
   //     Bitmap  ,       post      ,     final
   final Bitmap bmp=BitmapFactory.decodeByteArray(data, 0, data.length);
   handler.post(new Runnable() {   
   @Override
   public void run() {
    //  Post   UI  ImageView
    ivImage.setImageBitmap(bmp);
   }
   });
   //      
   dialog.dismiss();
  }
  } catch (Exception e) {
  e.printStackTrace();
  }
 }

 }
}
 효과 표시:

Message
Handler 가 sendmessage 방식 으로 메 시 지 를 메시지 큐 에 넣 으 려 면 Message 대상 을 전달 해 야 하 며,Handler 에 서 는 작업 스 레 드 에서 전 달 된 메 시 지 를 가 져 오 는 데 사용 할 handle Message()방법 을 다시 써 야 합 니 다.이 방법 은 UI 스 레 드 에서 실 행 됩 니 다.다음은 Message 를 소개 하 겠 습 니 다.
Message 는 final 클래스 이기 때문에 계승 할 수 없습니다.Message 는 스 레 드 에서 전 달 된 메 시 지 를 패키지 합 니 다.일반적인 데이터 에 대해 Message 는 getData()와 setData()방법 으로 데 이 터 를 가 져 오고 설정 합 니 다.그 중에서 작 동 하 는 데 이 터 는 Bundle 대상 입 니 다.이 Bundle 대상 은 일련의 getXxx()와 setXxx()방법 을 제공 하여 기본 데이터 형식의 키 쌍 을 전달 합 니 다.기본 데이터 형식 에 대해 서 는 간단 합 니 다.여 기 는 더 이상 상세 하 게 설명 하지 않 겠 습 니 다.한편,복잡 한 데이터 유형,예 를 들 어 한 대상 의 전달 은 상대 적 으로 복잡 해 야 한다.Bundle 에서 대상 을 전달 하 는 두 가지 방법 을 제 공 했 지만 이 두 가지 방법 도 해당 하 는 제한 이 있어 특정한 인 터 페 이 스 를 실현 해 야 한다.물론 일부 안 드 로 이 드 자체 의 유형 은 이 두 인터페이스 중의 하 나 를 실현 하여 직접 사용 할 수 있다.방법 은 다음 과 같다.
putParcelable(String key,Parcelable value):전달 해 야 할 대상 클래스 는 Parcelable 인 터 페 이 스 를 실현 합 니 다.
pubSerializable(String key,Serializable value):전달 해 야 할 대상 클래스 가 Serializable 인 터 페 이 스 를 실현 합 니 다.
또 다른 방식 으로 Message 에서 대상 을 전달 합 니 다.그것 은 Message 자체 가 가 진 obj 속성 전송 값 입 니 다.이것 은 Object 형식 이기 때문에 임의의 유형의 대상 을 전달 할 수 있 습 니 다.Message 자체 가 가 진 것 은 다음 과 같은 몇 가지 속성 이 있 습 니 다.
int arg 1:매개 변 수 는 복잡 하지 않 은 데 이 터 를 전달 하 는 데 사용 되 고 복잡 한 데 이 터 는 setData()로 전달 합 니 다.
int arg 2:매개 변수 2.복잡 하지 않 은 데 이 터 를 전달 하고 복잡 한 데 이 터 는 setData()로 전달 합 니 다.
Object obj:임의의 대상 을 전달 합 니 다.
int what:정 의 된 메시지 코드 는 일반적으로 메시지 의 표 지 를 설정 하 는 데 사 용 됩 니 다.
 Message 대상 에 대해 서 는 구조 적 방법 을 직접 사용 하 는 것 을 추천 하지 않 고 Message.obtain()이라는 정적 방법 이나 Handler.obtainMessage()를 사용 하여 얻 는 것 을 권장 합 니 다.Message.obtain()은 메시지 풀 에서 Message 대상 을 가 져 옵 니 다.메시지 풀 이 비어 있어 야 구조 적 방법 으로 새로운 Message 를 예화 할 수 있 습 니 다.그러면 메시지 자원 의 이용 에 유리 합 니 다.메시지 탱크 에 소식 이 너무 많 을 까 봐 걱정 할 필 요 는 없다.상한 선 이 있 고 상한 선 은 10 개다.Handler.obtainMessage()는 여러 가지 리 로드 방법 을 가지 고 있 으 며,원본 코드 를 보면 실제로 Handler.obtainMessage()가 내부 에서 도 호출 된 Message.obtain()임 을 알 수 있다.  
Message 가 온라인 으로 메 시 지 를 전달 하 는 것 이 므 로 먼저 하나의 데모 로 Message 의 사용 을 설명 하 시 겠 습 니까?아니면 일반적인 인터넷 에서 한 장의 그림 을 다운로드 하 는 Demo 입 니까?다운로드 한 후에 ImageView 컨트롤 로 보 여 줍 니 다.

package com.bgxt.datatimepickerdemo;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

public class HandlerMessageActivity1 extends Activity {
 private Button btnDown;
 private ImageView ivImage;
 private static String image_path = "http://ww4.sinaimg.cn/bmiddle/786013a5jw1e7akotp4bcj20c80i3aao.jpg";
 private ProgressDialog dialog;
 private static int IS_FINISH = 1;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.asynctask_activity);

 btnDown = (Button) findViewById(R.id.btnDown);
 ivImage = (ImageView) findViewById(R.id.ivSinaImage);

 dialog = new ProgressDialog(this);
 dialog.setTitle("    ");
 dialog.setMessage("    ,   ...");
 dialog.setCancelable(false);

 btnDown.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View v) {
   new Thread(new MyThread()).start();
   dialog.show();
  }
 });
 }

 private Handler handler = new Handler() {
 //  Handler     ,  handleMessage()  
 @Override
 public void handleMessage(Message msg) {  
  //         1
  if(msg.what==IS_FINISH){
  byte[] data=(byte[])msg.obj;
  Bitmap bmp=BitmapFactory.decodeByteArray(data, 0, data.length);
  ivImage.setImageBitmap(bmp);
  dialog.dismiss();
  }
 }
 };

 public class MyThread implements Runnable {

 @Override
 public void run() {
  HttpClient httpClient = new DefaultHttpClient();
  HttpGet httpGet = new HttpGet(image_path);
  HttpResponse httpResponse = null;
  try {
  httpResponse = httpClient.execute(httpGet);
  if (httpResponse.getStatusLine().getStatusCode() == 200) {
   byte[] data = EntityUtils.toByteArray(httpResponse
    .getEntity());
   //     Message  ,  what 1
   Message msg = Message.obtain();
   msg.obj = data;
   msg.what = IS_FINISH;
   //             
   handler.sendMessage(msg);
  }
  } catch (Exception e) {
  e.printStackTrace();
  }
 }
 }
}
효과 보 여주 기:

Message.obtain()방법 은 여러 가지 재 업로드 방법 을 가지 고 있 으 며,크게 두 가지 로 나 눌 수 있 습 니 다.하 나 는 Handler 대상 을 전달 하지 않 아 도 되 는 방법 입 니 다.이러한 방법 에 대해 서 는 메 시 지 를 채 우 면 Handler.sendmessage()방법 으로 메 시 지 를 보 내야 합 니 다.두 번 째 유형 은 Handler 대상 을 전달 해 야 합 니 다.이러한 방법 은 Message.sendToTarget()방법 으로 메시지 대기 열 에 메 시 지 를 보 낼 수 있 습 니 다.이것 은 Message 대상 에 개인 적 인 Handler 형식의 속성 Target 이 있 기 때 문 입 니 다.그 당시 obtain 방법 이 Handler 대상 에 전 달 될 때 Target 속성 에 값 을 부여 하고 sendToTarget()방법 을 호출 할 때실제 내부 에 서 는 Target.sendmessage()방법 을 호출 합 니 다.
Handler 에서 도 빈 메 시 지 를 보 내 는 방법 을 정의 했다.예 를 들 어 sendEmpty Message(int what),sendEmpty Message Delayed(int what,long delay Millis)는 이러한 방법 으로 Message 를 사용 하지 않 으 면 메 시 지 를 보 낼 수 있 는 것 처럼 보이 지만 소스 코드 를 보면 내부 도 Message.obtain()방법 에서 메시지 대상 을 얻 을 수 있다.그리고 속성 에 값 을 부여 하고 마지막 으로 sendmessage()를 사용 하여 메시지 대기 열 에 메 시 지 를 보 냅 니 다.
Handler 에서 Message 메 시 지 를 보 내 는 방법 은 다음 과 같 습 니 다.
Message obtainMessage():Message 대상 을 가 져 옵 니 다.
boolean sendmessage():메시지 대기 열 에 Message 대상 을 보 내 고 UI 스 레 드 에서 메 시 지 를 가 져 오 면 즉시 실행 합 니 다.
boolean sendmessage Delayed():메시지 대기 열 에 Message 대상 을 보 내 고 UI 스 레 드 에서 메 시 지 를 가 져 온 후 실행 을 지연 합 니 다.
boolean sendEmpty Message(int what):빈 Message 대상 을 대기 열 에 보 내 고 UI 스 레 드 에서 메 시 지 를 가 져 오 면 즉시 실행 합 니 다.
boolean sendEmpty MessageDelayed(int what,long delay Millis):메시지 대기 열 에 빈 Message 대상 을 보 내 고 UI 스 레 드 에서 메 시 지 를 가 져 온 후 실행 을 지연 합 니 다.
void removeMessage():메시지 대기 열 에서 응답 하지 않 은 메 시 지 를 제거 합 니 다.
다음은 작은 Demo 를 통 해 메 시 지 를 보 내 는 여러 가지 방법 을 보 여 드 리 겠 습 니 다.

package com.bgxt.datatimepickerdemo;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class HandlerMessageActivity2 extends Activity {
 private Button btn1, btn2, btn3, btn4,btn5;
 private static TextView tvMes;
 private static Handler handler = new Handler() {
 @Override
 public void handleMessage(android.os.Message msg) {
  if (msg.what == 3||msg.what==5) {
  tvMes.setText("what=" + msg.what + ",       ");
  } else {
  tvMes.setText("what=" + msg.what + "," + msg.obj.toString());
  }

 };
 };

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 // TODO Auto-generated method stub
 super.onCreate(savedInstanceState);
 setContentView(R.layout.message_activity2);
 tvMes = (TextView) findViewById(R.id.tvMes);
 btn1 = (Button) findViewById(R.id.btnMessage1);
 btn2 = (Button) findViewById(R.id.btnMessage2);
 btn3 = (Button) findViewById(R.id.btnMessage3);
 btn4 = (Button) findViewById(R.id.btnMessage4);
 btn5 = (Button) findViewById(R.id.btnMessage5);

 btn1.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View v) {
  //   Message.Obtain+Hander.sendMessage()    
  new Thread(new Runnable() {
   @Override
   public void run() {
   Message msg = Message.obtain();
   msg.what = 1;
   msg.obj = "  Message.Obtain+Hander.sendMessage()    ";
   handler.sendMessage(msg);
   }
  }).start();
  }
 });

 btn2.setOnClickListener(new View.OnClickListener() {

  @Override
  public void onClick(View v) {
  //   Message.sendToTarget    
  new Thread(new Runnable() {
   @Override
   public void run() {
   Message msg = Message.obtain(handler);
   msg.what = 2;
   msg.obj = "  Message.sendToTarget    ";
   msg.sendToTarget();
   }
  }).start();
  }
 });

 btn3.setOnClickListener(new View.OnClickListener() {
  //         
  @Override
  public void onClick(View v) {
  new Thread(new Runnable() {
   @Override
   public void run() {
   handler.sendEmptyMessage(3);
   }
  }).start();
  }
 });

 btn4.setOnClickListener(new View.OnClickListener() {

  @Override
  public void onClick(View v) {
  new Thread(new Runnable() {
   @Override
   public void run() {
   Message msg = Message.obtain();
   msg.what =4;
   msg.obj = "  Message.Obtain+Hander.sendMessage()      ";
   handler.sendMessageDelayed(msg, 3000);
   }
  }).start();
  }
 });
 
 btn5.setOnClickListener(new View.OnClickListener() {
  //           
  @Override
  public void onClick(View v) {
  new Thread(new Runnable() {
   @Override
   public void run() {
   handler.sendEmptyMessageDelayed(5, 3000);
   }
  }).start();
  }
 });
 }
}
 효과 전시


이상 은 안 드 로 이 드 핸들 러 에 대한 자 료 를 정리 하고 후속 적 으로 관련 자 료 를 계속 보충 하 는 것 입 니 다.본 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!

좋은 웹페이지 즐겨찾기