[Android] Handler, HandlerThread, AsyncTask
Handler
안드로이드 메세지 핸들러
Handler | Android Developers
사용법
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == Constants.WHAT_MESSAGE) {
// TODO UI process
}
}
}
public void mainThreadWork() {
someThreadWork(mHandler);
}
public void someThreadWork(final Handler mHandler) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Some another thread work
// If done this process
Message msg = new Message();
msg.what = Constants.WHAT_MESSAGE;
mHandler.sendMessage(msg);
}
}).start();
}
기본적인 구조는
- Handler를 만들고
- 다른 쓰레드에서 작업후
- 해당 Handler를 사용해 message 를 보내고
- UI 쓰레드에서 필요한 작업을 진행하는 것이다.
설명
Handler는 다른 쓰레드에서 UI Thread 의 작업이 필요할 경우 사용되는 방법 중 하나이다.
Callback 구조를 알고 있다면 그 구조와 비슷한 형태임을 알 수 있다.
// 콜백 인터페이스 생성
interface MyCallback {
void done(int arg1, int arg2);
}
MyCallback myCallback = new MyCallback() {
@Override
public void done(int arg1, int arg2) {
// TODO Main thread process
// 콜백이 호출 되었을때 진행됨
}
}
// 메인쓰레드에서 다른 쓰레드 호출
public void mainThreadWork() {
someCallbackWork(myCallback);
}
// 쓰레드 작업 완료후 콜백 반환
public void someThreadWork(final MyCallback callback) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Some another thread work
// If done this process
// 콜백을 통해 반환
callback.done(1, 2);
}
}).start();
}
이처럼 Callback과 비슷한 형태로 만들어진 Handler 에서는 Message 를 다룰 수 있는 부가적인 메서드들이 포함되어 있다.
이러한 Handler 가 필요한 이유는 UI Thread 를 Blocking 하지않고 비동기적인 작업을 할 수 있도록 제공하기 때문이다. 즉, UI 작업과 다른 작업을 분리하기 위함인데, 안드로이드에서는 Handler를 응용한 다양한 클래스 들을 제공하고 있다.
HandlerThread
위와 같은 구조를 응용해서 만들어진 것이 바로 HandlerThread 이다.
HandlerThread | Android Developers
사용법
private Handler mHandler;
private HandlerThread handlerThread;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handlerThread = new HandlerThread("Handler Thread");
handlerThread.start(); // 여기서 쓰레드를 실행시켜둔다.
// Handler 를 새로 만들때 HandlerThread의 Looper를 넣어준다.
mHandler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
if(msg.what == Constants.CLICKED) {
// TODO Background work
}
}
}
Button sendToHandlerThread = (Button) findViewById(R.id.send);
sendToHandlerThread.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 만들어둔 핸들러를 이용하여 다른 쓰레드에 메세지를 보낸다.
Message msg = mHandler.obtainMessage();
message.what = Constants.CLICKED;
mHandler.sendMessage(msg);
}
});
}
@Override
public void onDestroy() {
// HandlerThread는 백그라운드에서 Looper가 계속 돌고 있으므로 별도로 종료시켜 주어야 한다.
handlerThread.quit();
super.onDestroy();
}
설명
HandlerThread 는 안드로이드 백그라운드에서 돌며 순차적으로 메세지를 처리할 수 있는 MessageQueue를 제공한다.
사용방법은
- 내부적으로 구현된 Looper를 통해 먼저 쓰레드를 실행시키고
- 외부에서 선언된 Handler를 이용해 메세지를 받고
- 백그라운드 작업을 실시한다.
- 일정 작업후 quit() 호출을 하여 명시적으로 Looper를 종료시킨다.
이렇게 HandlerThread 를 이용하게 되면 좀더 편리하게 쓰레드를 구분할 수 있다.
AsyncTask
AsyncTask 도 위와 같이 Handler와 백그라운드 쓰레드를 이용한 비동기 처리를 위해 사용되는 클래스이다.
AsyncTask | Android Developers
사용법
TextView networkTextView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button networkButton = (Button) findViewById(R.id.send);
networkTextView = (TextView) findViewById(R.id.net_response);
// 버튼 클릭시 네트워크 작업을 실행시킨다.
networkButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
new AsyncTask<String, Void, String>() {
@Override
protected String doInBackground(String... urls) {
// AsyncTask Thread
// 네트워크 요청을 하고 응답메세지를 반환한다.
return someNetworkWork(urls[0]);
}
@Override
protected void onPostExecute(String responseMessage) {
// UI Thread
// 반환된 응답 메세지를 TextView에 반영한다.
netwrokTextView.setText(responseMessage);
}
}.execute("http://test.url.com/test");
}
});
}
설명
AsyncTask 의 doInBackground() 에서는 쓰레드를 생성하여 백그라운드 작업을 실행하고
작업이 끝난후 onPostExecute() 에서 UI 쓰레드로 전달된다.
이 쓰레드는 UI 쓰레드 이므로 TextView 를 변경하는 등의 작업이 가능해진다.
위에서 설명한 방법에 비해서 훨씬 간결해진 문장을 볼 수 있다.
결론
Handler, HandlerThread, AsyncTask 의 기본적인 사용법과 안드로이드에서 백그라운드 작업하는 방법을 보았다.
이들 각각의 장단점이 있기 때문에 어느것이 더 나은 것이라기 보다 상황에 따라서 적절하게 사용하는 것이 좋다.
안드로이드는 UI Thread 가 MainThread 이고 이 안에서 할 수 있는 작업이 한정되어 있기 때문에 쓰레드를 적절히 생성해서 작업을 해야한다.
다만 주의할 점은 다른 쓰레드에서도 Context 가 필요한 상황이 생기는데, 이때 쓰레드로 Context를 전달해주게 되는데, 여기서 쓰레드가 정확히 종료되지 않으면 Memory Leak이 발생하게 된다. 이는 다음 글에서 다루어 보도록 한다.
'android' 카테고리의 다른 글
[Android] 안드로이드의 SWAP (0) | 2017.07.18 |
---|