|
Handler란?
한 스레드는 그 내부의 연산만 가능하며 다른 스레드의 UI를 건드릴 수 없습니다. 그런데 만약 스레드들이 서로 영향을 줄 수 없다면 스레드의 존재 이유가 없을 것입니다. 이를 해결하기 위해서 서로 다른 스레드 간의 참조를 위해서 스레드 간에 통신할 수 있는 장치를 만들었는데 그것이 핸들러[Handler]입니다. 핸들러는 스레드 간에 메시지 객체나 러너블 객체를 통해 통신할 수 있는 장치이며,하나 의 핸들러는 하나의 스레드와 관련을 맺습니다. 핸들러는 자신이 생성된 스레드에 짝이 되며 다른 스레드와 통신을 수행하게 됩니다. |
Handler의 메시지 수령
핸들러에 메시지가 도착하게 되면 아래의 메서드가 호출됩니다. public void handleMessage(Message msg) 인수로 메시지 객체를 전달 받는데 이는 스레드 간에 통신을 해야 할 내용에 관한 객체입 니다. 몇가지 정보가 추가 될 수 있기 때문에 여러 개의 필드를 가지고 있습니다. 메시지 필드 : 설명 1. int what : Message의 ID 2. int arg1 : Message가 보낼 수 있는 첫번째 정보. 3. int arg2 : Message가 보낼 수 있는 두번째 정보. 4 Object obj : Integer로 표현 불가능 할 경우 객체를 보냄. 5. Messenger replyTo : 응답을 받을 객체를 지정. |
Handler의 메시지 전송
Message를 전송할 때는 다음의 메서드를 사용합니다. 1. boolean Hanler.sendEmptyMessage(int what); - Message 의 ID에 해당하는 값을 전달할 때 사용함. 2. boolean Handler.sendMessage(Message msg); - ID만으로 불가능하고 좀 더 내용이 있는 정보를 전송할 때 사용. 3. boolean sendMessageAtFrontOfQueue(Message msg); - 메시지가 큐에 순서대로 쌓여서 FIFO(First In Frist Out)형태로 처리되지만, 이 메서드를 사용하면 노래방에서 우선 예약 하듯이 사용가능합니다. |
Handler의 발송과 수령 예제
//Handler 시작 부분 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); BackThread thread = new BackThread(); thread.setDaemon(true); thread.start(); } //Handler Class class BackThread extends Thread { @Override public void run() { // TODO Auto-generated method stub while(true) { //처리 내용 //핸들러 메세지 보내는 부분 mHandler.sendEmptyMessage(0); try { Thread.sleep(1000); } catch (Exception e) { // TODO: handle exception ; } } }; //핸들러를 받아서 처리할 내용 Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { if(msg.what == 0){ //처리할 내용 } }; } } |
Handler의 객체
전송
앞선 메서드로 특정 정보를 보낼 수 있지만 메시지를 보내는 대신에 객체를 보낼 수도 있습니다. boolean post(Runnable r) 핸들러로 다음의 매서드를 통해 Runnable 객체를 보내면 해당 객체의 run 메서드가 실행됩니다. 이럴 경우 메시지를 받는 쪽은 다른 것을 정의하지 않고 핸들러만 정의하면 해당 내용을 수행할 수 있습니다. |
Handler의 객체 전송 예제
class BackThread extends Thread { @Override public void run() { // TODO Auto-generated method stub while(true) { //처리 내용 mHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub // 객체를 받아서 처리할 내용 } }); try { Thread.sleep(1000); } catch (Exception e) { // TODO: handle exception ; } } } //핸들러를 받아서 처리할 내용 Handler mHandler = new Handler(); } |
클래스의 분리 시 메시지 교환
앞선 예제처럼 스레드가 이너 클래스로 구현되었을 경우 멤버의 공유가 가능하지만 그렇 지 않고 분리된 클래스의 경우에는 더 상세한 코드의 구현이 필요합니다. 이경우 스레드는 전달 받은 핸들러를 자신의 멤버로 따로 저장해야 하고 (공유가 불가능 하기 때문입니다.) 메시지 객체에 추가 정보를 저장해서 보내야 합니다. |
클래스 분리시 메시지 교환 예제
public class TestSampleProject extends Activity { int mManinValue = 0; int mBackValue = 0; TextView mMainText; TextView mBackTest; BackThread thread; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); thread = new BackThread(mHandler ); thread.setDaemon(true); thread.start(); } Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { if(msg.what == 0) { //처리할 내용 } }; }; } class BackThread extends Thread { Handler mHandler; public BackThread(Handler handler) { // TODO Auto-generated constructor stub mHandler = handler; } @Override public void run() { // TODO Auto-generated method stub Message msg = new Message(); msg.what = 0; msg.arg1 = 1; mHandler.sendMessage(msg); try { Thread.sleep(1000); } catch (Exception e) { // TODO: handle exception } } } |
메시지 풀의 사용
매번 핸들러를 구현할 때마다 new 연산자로 새로 생성한다면 메모리도 계속해서 사용할 것이고 그에 다른 가비지
컬렉션의 작업도 생길 것입니다. 이러면 속도도 느려지는 결과가 발생합니다. 이런 경우를 보완하고자 메시지 풀 이라는 임시 캐쉬를 유지시켜서 빠른 작업이 가능하게 합니다. static Message obtain(message orig) static Message obtain(Handler h, int what, int arg1, int arg2, Object obj) - obtain 메서드는 메시지 풀에서 비슷한 메시지가 있다면 이를 재사용하게 합니다. void recycle() - 사용한 메시지를 풀에 집어 넣는 역할을 하는데 풀에 한번 집어 넣게 되면 시스템이 관리하므로 더 이상 관여할 수 없습니다. |
메시지 풀의 사용 예제
... class BackThread extends Thread { Handler mHandler; public BackThread(Handler handler) { // TODO Auto-generated constructor stub mHandler = handler; } @Override public void run() { // TODO Auto-generated method stub while(true) { //처리할 내용 Message msg = Message.obtain(mHandler, 0 , 1 , 0); mHandler.sendMessage(msg); try { Thread.sleep(1000); } catch (Exception e) { // TODO: handle exception } } } } |
http://markan82.tistory.com/34
스레드
스레드는 여러개의 작업을 동시에 할때 필요하다. 데이터를 미리 받아서 준비해 놓거나 백그라운드로 음악을 재생할 수 도 있다.
단, 스레드를 사용할때에는 스레드간의 동기화를 고려하여 소프트웨어를 설계하여야 한다.
백드라운드 스레드는 내부적인 연산만을 해야 하며 다른 스레드 소속의 UI는 건들 수 없다. 그래서 스레드간의 통신을 할 수 있는 핸들러를 사용한다. 다음 예제를 보자
예제 소스
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 ThreadTest extends Activity {
int mMainValue = 0;
TextView mMainText;
TextView mBackText;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mMainText = (TextView)
findViewById(R.id.minValue);
mBackText = (TextView)
findViewById(R.id.backValue);
Button increaseBtn = (Button)
findViewById(R.id.increase);
increaseBtn.setOnClickListener(onClick);
//스레드 객체를
생성합니다.
BackThread thread = new BackThread(mHandler);
//데몬
스레드는 메인 스레드가 종료될때 강제 종료됨
//무한루프 스레드의 경우에는 데몬스레드로 지정하지 않으면 결코 죽지
않는다.
thread.setDaemon(true);
thread.start();
}
View.OnClickListener onClick = new View.OnClickListener()
{
public void onClick(View v)
{
mMainValue++;
mMainText.setText("MainValue : " +
mMainValue);
}
};
Handler mHandler = new Handler()
{
public void handleMessage(Message msg) {
if(msg.what == 0)
{
mBackText.setText("BackValue : " +
msg.arg1);
}
}
};
}
class BackThread extends Thread {
int mBackValue = 0;
Handler
mHandler;
BackThread(Handler handler) {
mHandler =
handler;
}
public void run() {
while(true) {
//무한 반복하면서
1초에 1씩 증가
mBackValue++;
Message msg = Message.obtain(mHandler, 0,
mBackValue, 0);
mHandler.sendMessage(msg);
try
{
Thread.sleep(1000);
} catch(InterruptedException e)
{}
}
}
}
'차근차근 > Android' 카테고리의 다른 글
안드로이드 @override (0) | 2014.07.29 |
---|---|
처음 보는 APK에 Main Activity를 어떻게 찾을까? (0) | 2014.07.29 |
[Android] WebView에서 HTML5 사용을 위한 WebSettings 설정 (0) | 2014.07.29 |
shouldOverrideUrlLoading(WebView view, String url) (0) | 2014.07.29 |
WebChromeClient 사용하기 (0) | 2014.07.29 |