- Today
- Total
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 재능이의 돈버는 일기
- StresslessLife
- K_JIN2SM
- 소소한 일상
- My Life Style & Memory a Box
- Blog's generation
- 공감 스토리
- 취객의 프로그래밍 연구실
- Love Me
- Dream Archive
- 세상에 발자취를 남기다 by kongmingu
- hanglesoul
- 카마의 IT 초행길
- 느리게.
- 미친듯이 즐겨보자..
- Joo studio
- Gonna be insane
- 악 다 날아갔어!! 갇대밋! 왓더...
- xopowo05
- 맑은공기희망운동
- 엔지니어 독립운동
- 혁준 블로그
- Simple in Complex with Simple
- 무의식이 의식을 지배한다
드럼치는 프로그래머
[안드로이드] 안드로이드의 스레드(Thread) - B. 핸들러 본문
B. 핸들러
핸들러(Handler)
한 스레드는 그 내부의 연산만 가능하며 다른 스레드의 UI를 건드릴 수 없습니다. 그런데 만약 스레드들이 서로 영향을 줄 수 없다면 스레드의 존재 이유가 없겠죠.
이런 서로 다른 스레드 간의 참조를 위해서 스레드 간에 통신할 수 있는 장치를 만들었는데 그것이 핸들러입니다. 핸들러는 스레드 간에 메시지 객체나 러너블 객체를 통해 통신할 수 있는 장치이며, 하나의 핸들러는 하나의 스레드와 관련을 맺습니다. 핸들러는 자신이 생성된 스레드에 짝이 되며 다른 스레드와 통신을 수행하게 됩니다.
핸들러의 메시지 수령
핸들러에 메시지가 도착하게 되면 아래의 메서드가 호출됩니다.
public void handleMessage(Message msg)
인수로 메시지 객체를 전달받는데 이는 스레드 간에 통신을 해야 할 내용에 관한 객체입니다. 몇 가지 정보가 추가 될 수 있기 때문에 여러 개의 필드를 가지고 있습니다.
메시지의 필드 |
설명 |
int what |
메시지의 ID라고 볼 수 있다. |
int arg1 |
메시지가 보낼 수 있는 정보이다. |
int arg2 |
메시지가 보낼 수 있는 또 다른 정보이다. |
Object obj |
Integer로 표현 불가능 할 경우 객체를 보낸다. |
Messenger replyTo |
응답을 받을 객체를 지정한다. |
핸들러의 메시지 전송
메시지를 전송할 때는 다음의 메서드를 사용합니다.
boolean Handler.sendEmptyMessage(int what)
메시지의 ID에 해당하는 값을 전달할 때 사용할 수 있습니다.
boolean Handler.sendMessage(Message msg)
ID만으로 불가능하고 좀 더 내용이 있는 정보를 전송할 때 사용합니다.
boolean sendMessageAtFrontOfQueue(Message msg)
메시지가 큐에 순서대로 쌓여서 FIFO(First In First Out)형태로 처리되지만 이 메서드를 사용하면 노래방에서 우선예약 하듯이 사용가능합니다.
핸들러의 발송과 수령 예제
public class HandlerTest extends Activity {
int mMainValue = 0;
int mBackValue = 0;
TextView mMainText;
TextView mBackText;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.thread_threadtest);
mMainText = (TextView)findViewById(R.id.mainvalue);
mBackText = (TextView)findViewById(R.id.backvalue);
Button btn = (Button)findViewById(R.id.increase);
btn.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
mMainValue++;
mMainText.setText("MainValue : " + mMainValue);
}
});
BackThread thread = new BackThread();
thread.setDaemon(true);
thread.start();
}
class BackThread extends Thread {
public void run() {
while (true) {
mBackValue++;
mHandler.sendEmptyMessage(0);
try { Thread.sleep(1000); } catch (InterruptedException e) {;}
}
}
}
Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == 0) {
mBackText.setText("BackValue : " + mBackValue);
}
}
};
}
핸들러의 객체 전송
앞선 메서드로 특정 정보를 보낼 수 있지만 메시지를 보내는 대신에 객체를 보낼 수도 있습니다.
boolean post(Runnable r)
핸들러로 다음의 매서드를 통해 Runnable 객체를 보내면 해당 객체의 run 메서드가 실행됩니다. 이럴 경우 메시지를 받는 쪽은 다른 것을 정의하지 않고 핸들러만 정의하면 해당 내용을 수행할 수 있습니다.
핸들러의 객체 전송 예제
class BackThread extends Thread {
public void run() {
while (true) {
mBackValue++;
mHandler.post(new Runnable() {
public void run() {
mBackText.setText("BackValue : " + mBackValue);
}
});
try { Thread.sleep(1000); } catch (InterruptedException e) {;}
}
}
}
Handler mHandler = new Handler();
}
클래스의 분리 시 메시지 교환
앞선 예제처럼 스레드가 이너 클래스로 구현되었을 경우 멤버의 공유가 가능하지만 그렇지 않고 분리된 클래스의 경우에는 더 상세한 코드의 구현이 필요합니다.
이 경우 스레드는 전달 받은 핸들러를 자신의 멤버로 따로 저장해야 하고 (공유가 불가능 하기 때문입니다) 메시지 객체에 추가 정보를 저장해서 보내야 합니다. 예제를 보는게 더 이해하기 편하죠.
클래스의 분리 시 메시지 교환 예제
public class HandlerTest extends Activity {
int mMainValue = 0;
TextView mMainText;
TextView mBackText;
BackThread mThread;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.thread_threadtest);
mMainText = (TextView)findViewById(R.id.mainvalue);
mBackText = (TextView)findViewById(R.id.backvalue);
Button btn = (Button)findViewById(R.id.increase);
btn.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
mMainValue++;
mMainText.setText("MainValue : " + mMainValue);
}
});
mThread = new BackThread(mHandler);
mThread.setDaemon(true);
mThread.start();
}
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) {
mBackValue++;
Message msg = new Message();
msg.what = 0;
msg.arg1 = mBackValue;
mHandler.sendMessage(msg);
try { Thread.sleep(1000); } catch (InterruptedException e) {;}
}
}
}
메시지 풀의 사용
매번 핸들러를 구현할 때마다 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 {
int mBackValue = 0;
Handler mHandler;
BackThread(Handler handler) {
mHandler = handler;
}
public void run() {
while (true) {
mBackValue++;
// 앞서서 new Message를 선언해서 what과 argument를 전해 주었던 것과 달리
// 메시지 풀에서 what과 argument가 있는지 찾아보고 가져오게 됩니다.
// 얼마 안되는 횟수라면 상관없지만 몇백, 몇천번 반복하는 연산이라면 의미가 있겠죠.
Message msg = Message.obtain(mHandler, 0, mBackValue, 0);
mHandler.sendMessage(msg);
try { Thread.sleep(1000); } catch (InterruptedException e) {;}
}
}
}
[출처] 안드로이드의 스레드(Thread) - B. 핸들러|작성자 녹차
'★─Programing > ☆─Android' 카테고리의 다른 글
[안드로이드] 안드로이드 토스트 (Toast) (0) | 2011.11.03 |
---|---|
[안드로이드] 안드로이드의 스레드(Thread) - C. 루퍼(Looper) (0) | 2011.11.03 |
[안드로이드] 안드로이드의 스레드(Thread) - A. 스레드 (0) | 2011.11.03 |
[안드로이드] 안드로이드 핵심, 액티비티(Activity) (0) | 2011.11.03 |
[안드로이드] 안드로이드 프로젝트 폴더와 파일 설명 (0) | 2011.07.22 |