안드로이드 지식 공유
Handler 에 대한 이해
안드로이드를 개발하면서 Handler 에 대해서 과연 알고 사용하는 것인가? 에 대한 의문이 들었습니다. 편해서 혹은 그냥 아무생각 없이 핸들러를 너무도 막 사용하기 때문이죠. 그게 틀렸다는게 아니고 알고 쓰면 더 좋겠다!! 라는 생각에서 정리해보려 합니다^^
https://developer.android.com/reference/android/os/Handler
Handler 는 안드로이드 API 1 레벨 부터 사용되어진 매우 익숙한 존재입니다. 비동기적으로 처리해야할 로직을 아주 간단하게 그리고 편리하게 처리할 수 있죠. 사실 내부에 어떤 방식으로 동작하는지에 대해서는 굳이 알필요가 없을 수도 있습니다. 그냥 편하게 쓰고자 하면 말이죠.
1
2
3
4
5
6
7
8
9
10
11
12
|
public Handler mHandler;
...
mHandler = new Handler();
mHandler.post(new Runnable(){
@override
public void run(){
...
}
});
|
이건 우리가 자주 쓰는 구조 인데요. 개발 초기에는 이게 뭔지도 모르고 사용 했었죠. 예전에 웹 개발만 하다보니 쓰레드에 대한 이해가 많이 부족 했었죠. Handler 자체는 쓰레드의 동작과 연관이 깊습니다. 왜냐면 Handler 자체가 비동기 방식을 편하게 컨트롤 할수 있도록 만들어 논 것이기 때문이죠 ^^; (안드로이드를 잘 만들기? 위해서는 쓰레드에 대한 어느정도 깊이있는 이해가 필요하다고 생각합니다. 그냥 개인적인 생각입니다^^;
)
Handler 는 new Handler() 에서 new 를 만나게 되면서 객체가 생성되게 되는데요. 이때 내부적으로 Looper 와 MessageQueue 라는 놈과 연관지어 지게 됩니다. 객체를 생성 하게 되면 그 객체를 생성한 쓰레드에 Looper와 MessageQueue에 바인딩 되어지게 됩니다. 즉 이 3종세트가 handler 사용에 연관된 전부다. 라고 생각하면 쉬울것 같습니다. 위에 간단한 소스 코드를 보면 사실 post 메서드는 runnable 태스크를 queue에 전달하여 그 메세지는 Looper에 의해 꺼내져 해당 동작을 수행하게 됩니다. 이게 다 입니다! ^^; 참 쉽죠잉.
자 그럼 저기서 Handler는 누구의 Handler 입니까?
누구긴요. ㅎㅎ new를 실행한 쓰레드의 핸들러지요. 이제 이해가 좀 되시죠? 우리가 따로 쓰레드를 생성하지 않았다면 저건 메인쓰레드의 Handler가 분명합니다. 자 그럼 좀더 비동기적인 접근을 위해 백그라운드 쓰레드를 운용하여 handler를 사용하는 방법을 알아보겠습니다.
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
|
...
private static class LooperThread extends Thread{
public Handler mhandler;
@Override
public void run() {
Looper.prepare(); //핸들러와 루퍼 큐의 연결
mhandler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what == 0){
doLongRunningOperation();
}
}
};
Looper.loop(); //루퍼 시작 (run이 끝나지 않음을 보장하는 차단적 메서드)
}
private void doLongRunningOperation(){
// 동작 구현 ...
}
}
|
cs |
액티비티 안에 간단한 이너 클래스를 구현하였습니다. 쓰레드를 상속하며 내부적으로 핸들러를 구현하고 있죠. 여기서 특이한 점은 run메서드 안에 있는 Looper.prepare() 와 Looper.loop() 입니다. 이 메서드 들을 통해 핸들러와 looper, queue가 유기적으로 결합되어 우리가 보내는 핸들러 메세지를 지속적으로 받을수 있게 됩니다.
그렇다면 우리가 메인쓰레드에서 핸들러를 사용할때는 왜 이런 일련의 작업들을 해주지 않은것이죠??
메인쓰레드의 경우 다른 쓰레드와 다르게 좀 특이한데요. 메인쓰레드는 태생적으로 Looper에 대한 셋팅을 자동으로 가지고 있습니다.그래서 우리가 해줄 필요가 없는것이죠. 또한 메인루퍼는 전역적인 접근( getMainLooper() 메서드를 통해 )이 가능한 유일한 놈이죠. 어디서든 메인루퍼로의 접근이 가능합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
private LooperThread mlooperThread;
private Button btnClick;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_basic_handler);
btnClick = findViewById(R.id.btnClick);
btnClick.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
//루퍼 쓰레드에게 (핸들러를 통해)임무 전달
//그러면 그 핸들러가 자신의 큐에 메세지를 넣고 그 루퍼가 메세지를 꺼내 실행한다
mlooperThread.mhandler.obtainMessage();
mlooperThread.mhandler.sendEmptyMessage(0);
}
});
//루퍼스레드 동작
mlooperThread = new LooperThread();
mlooperThread.start();
}
|
cs |
비동기 방식의 핸들러 사용을 정의 했으니, 이제 사용해 봐야죠. 화면에 버튼을 만들고 그에 따른 동작을 구현합니다. 화면이 그려질때 루퍼쓰레드를 start 해주는것도 잊으면 안되겠죠? 버튼을 누르면 작업쓰레드의 핸들러로 빈 메세지 하나를 전달합니다. 그럼 그 메세지는 큐에 저장되고 루퍼는 그걸 다시 핸들러에게 전달하여 드디어 메세지에 해당하는 동작이 실행되어 집니다. 이렇게 우리는 백그라운드 쓰레드를 사용하여 비동기적인 방식으로 작업을 할 수 있게 되었습니다. 다음은 안드로이드에서 제공하는 핸들러 쓰레드를 사용하여 좀 더 편리하게 작업하는 방법을 알아보겠습니다. 그럼 이만!
본 글은 인터넷, 책, 등으로 습득한 지식을 토대로 내용을 전달하고자 하며 개인적으로는 정리하는 개념으로 사용하고자 작성되었습니다. 틀린점이 있을 수 있다는 점 양해 부탁 드리며, 그저 참고용 으로 봐주시면 감사하겠습니다.
'개발 코딩 정보 공유 > 안드로이드 자바 코틀린' 카테고리의 다른 글
자바 메모리 Stack 과 Heap 영역에 대하여 (0) | 2018.08.18 |
---|---|
안드로이드 웹뷰 핀치 줌 인 / 아웃 (0) | 2018.08.18 |
UI쓰레드에서 긴작업을 하면 안되는 이유 (0) | 2018.08.14 |
HandlerThread 의 활용 (0) | 2018.08.12 |
초보강좌 안드로이드 일단 만들어 봅시다 (0) | 2018.08.09 |