일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 끝말잇기
- 함수형 프로그래밍
- 안드로이드
- 한달어스
- 브런치작가되기
- 면접
- 목적중심리더십
- 소프시스
- 소프시스 밤부 좌식 엑슬 테이블
- 커스텀린트
- 아비투스
- 테트리스
- 캐치마인드
- 한달브런치북만들기
- 목적 중심 리더십
- 지지않는다는말
- 한달독서
- 슬기로운 온라인 게임
- 베드테이블
- T자형인재
- 자취필수템
- 프래그먼트
- 1일1커밋
- 재택근무
- 한단어의힘
- 베드트레이
- 리얼하다
- 북한살둘레길
- 좌식테이블
- 어떻게 나답게 살 것인가
- Today
- Total
정상에서 IT를 외치다
[Android, Handler] Handler 넌 무엇이더냐? 본문
안녕하세요. 블랙진입니다.
지난 시간 "Thread 넌 무엇이더냐?" 를 포스팅 했습니다. 이 때 Handler가 필요한 상황에 대해 언급을 했습니다. 그럼 지난 포스팅에 이어 Handler 에 대해 알아보겠습니다.
핸들러란?
A Handler allows you to send and process Message
and Runnable objects associated with a thread's MessageQueue
.
- 구글문서
구글문서에는 Message 와 MessageQueue 를 통해 설명하고 있습니다. Handler 를 이해하기 위해서는 Message, MessageQueue 그리고 Looper 에 대해 알고 있어야 합니다. 알아야 될게 너무 많네요 ㅠㅜ.... 그럼 하나하나 개념을 정리해 보겠습니다.
여기 그림으로 잘 정리해된 자료가 있어 가지고와 봤습니다. 물론 출처에 걸린 링크를 통해 해당 블로그에서 더 많은 정보를 얻으실 수 있습니다.
프로그램 안에서 실행을 담당하는 하나의 흐름
Message 를 담는 자료구조
Parcelable 형태의 객체로 Message 클래스를 보면 어떤 형태의 데이터가 전달되는지 확인 할 수 있습니다.
public final class Message implements Parcelable {
public static final Creator<Message> CREATOR = null;
public int arg1;
public int arg2;
public Object obj;
public Messenger replyTo;
public int sendingUid = -1;
public int what;
....
}
그림에서와 같이 스레드당 1개씩 가지고 있습니다. 또한 Looper 별로 MessageQueue를 가지고 있습니다. MessageQueue 에서 Message 를 꺼내 Handler 로 전달하는 작업을 처리합니다. 메인스레드에서는 Looper 를 이미 가지고 있어 개발자가 관여하지 않아도 되지만 작업스레드에서는 Looper 를 직접 작성하고 실행시켜야 합니다.
<Looper를 생성하는 방법>
-> Looper.prepare() : 작업스레드를 위한 루퍼를 준비한다.
-> Looper.loop() : 큐에서 메시지를 꺼내 핸들러로 전달한다.
class LooperThread extends Thread {
public Handler mHandler;
@Override
public void run() {
Looper.prepare();
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
}
};
Looper.loop();
}
}
자 그럼 다시한 번 Handler 에 대해 정의해 보겠습니다.
- 서로 다른 쓰레드간의 통신을 위한 장치로 쓰인다
- MessageQueue 에 보낼 데이터를 넣고 Looper 를 통해 처리할 데이터를 받고 보내는 중간 브로커 같은 역활을 합니다.
- 기본 생성자를 통해 Handler 를 생성하면 해당 Handler 를 호출한 스레드의 MessageQueue 와 Looper 에 자동 연결된다.
예제
public class MainActivity extends AppCompatActivity {
private int mMainValue = 0;
private int mSubValue = 0;
private TextView mainText, subText;
private Handler mHandler;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainText = findViewById(R.id.mainText);
subText = findViewById(R.id.subText);
findViewById(R.id.btnIncrease).setOnClickListener(view -> {
mMainValue++;
mainText.setText(String.valueOf(mMainValue));
});
// 기본 생성자를 통해 Handler 를 생성하면
// 해당 Handler 를 호출한 스레드의 MessageQueue 와 Looper 와 자동 연결된다.
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if(msg.what == 0) {
subText.setText(String.valueOf(mSubValue));
}
}
};
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
mSubValue++;
//sendEmptyMessage 함수를 통해 데이터 전달
//파라미터로 보낸 값은 message의 what에 대입됩니다.
mHandler.sendEmptyMessage(0);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.setDaemon(true);
thread.start();
}
}
이번에는 MainAcitivty.class 외부에서 초기화 하는 예제입니다.
public class ExerciseActivity extends AppCompatActivity {
private int mMainValue = 0;
private int mSubValue = 0;
private TextView mainText, subText;
private Handler mHandler;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_exercise);
mainText = findViewById(R.id.mainText);
subText = findViewById(R.id.subText);
findViewById(R.id.btnIncrease).setOnClickListener(view -> {
mMainValue++;
mainText.setText(String.valueOf(mMainValue));
});
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if(msg.what == 0) {
mSubValue = msg.arg1;
subText.setText(String.valueOf(mSubValue));
}
}
};
BackThread backThread = new BackThread(mHandler);
backThread.setDaemon(true);
backThread.start();
}
}
class BackThread extends Thread {
int backValue = 0;
Handler handler;
BackThread(Handler handler){
this.handler = handler;
}
@Override
public void run() {
while(true){
backValue++;
// 메세지를 생성
//Message msg = new Message();
Message msg = Message.obtain();
msg.what = 0;
msg.arg1 = backValue;
handler.sendMessage(msg); // 메인스레드의 핸들러에 메세지 보내기
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Handler 를 BackThread의 생성자로 보내 외부 클래스에서 메인스레드에 접근할 수 있는 중간 브로커 역활을 해줍니다.
정리
지난 포스팅(Thread 넌 무엇이더냐?)에 이어 스레드와 핸들러에 대해 설명했습니다. 안드로이드 앱에서는 오직 Main 스레드에서만 View 를 업데이트 할 수 있습니다. 이러한 점을 명심하고 Thread 와 Handler 를 사용하면 더욱 안정적인 멋진 앱을 만드실 수 있을 겁니다 :)
<참고자료>
'안드로이드' 카테고리의 다른 글
[Android, Cache, Bitmap] 내부저장소에 비트맵 저장하기 (8) | 2019.04.03 |
---|---|
[Android, Glide] Glide BitmapTransform 파헤쳐 보자! (2) | 2019.03.26 |
[Android, Thread] Thread 넌 무엇이더냐? (0) | 2019.03.26 |
[Android, ExoPlayer2] ExoPlayer2 개념 및 사용방법 (3) | 2019.03.25 |
[Android, MediaPlayer] MediaPlayer 를 이용한 동영상 재생 (0) | 2019.03.25 |