Android Thread Handler
Process : Program의 instance
Process 간에는 메모리를 공유하지 않는다.
Thread : 작업을 수행하는 객체로 Scheduler에 의해 관리, 실행된다.
Process는 1개 이상의 Thread를 갖는다.
같은 Process 내에 Thread들은 메모리를 공유한다.
Process : 회사
MainThread : 대표
Thread : 직원
Resource : 프린터 등등 자원
* 자원은 다른 회사(Process)와 공유하지 않는다.
Thread 사용하는 방법
1) Runnable 이용
2) Thread 상속
ThreadPool : 몇 개의 Thread로 여러 작업을 수행하게 한다. (Thread 재활용)
ThreadPoolExecutor로 생성
ThreadLocal : Thread만 가지고 있는 자원 관리
Thread Annotation : 함수 호출시 해당 Thread로 호출되는지 확인하기 위해 사용됨
Message Loop
어떤 작업을 반벅해서 처리해야할때 사용
Event Driven 방식
Handler : Message Queue에 Message를 집어넣기위한 class
Thread간에 메시지를 주고받을때 사용한다.
Handler의 handlerMessage()로 Message를 어떻게 처리할지 정의할 수 있다.
- Handler 객체 생성
: 해당 thread로 Message를 전달하는 hander가 만들어진다.
Handler handler = new Handler();
: handler를 실행하는 Thread의 Message Queue로 Message를 보내는 handler를 생성한다.
- Message 객체 생성
obtainMessage()로 전달할 Message 객체를 생성
obtainMessage(what,
arg1, arg2
Object) 등을 파라미터로 전달할 수 있다.
what은 Message Type을 의미한다.
- Message 객체 전달
방법1) sendMessage로 Message를 thread에 전달한다.
방법2) Message Queue에 Runnable을 전달한다.
- Message 처리
* 화면갱신은 MainThread만 처리가능
public class MainActivity extends AppCompatActivity {
ProgressBar progressBar;
TextView tvMessageView;
public static final int MESSAGE_PROGRESS = 0;
public static final int MESSAGE_DONE = 1;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case MESSAGE_PROGRESS:
int progress = msg.arg1;
progressBar.setProgress(progress);
tvMessageView.setText(" " + progress);
break;
case MESSAGE_DONE:
progressBar.setProgress(100);
tvMessageView.setText("done!");
break;
}
}
};
protected void onCreate(Bundle savedInstanceState) {
btn.setOnClickListener(new View.setOnClickListener() {
public void onClick(View v) {
// Thread
new Thread(new Runnable() {
@Override
public void run() {
int count = 0;
while(count < 20) {
Message msg = handler.obtainMessage(MESSAGE_PROGRESS, count * 5, 0);
// MainThread한테 화면 갱신 좀 해줘
handler.sendMessage(msg);
count++;
}
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
}
Message msg = handler.obtainMessage(MESSAGE_DONE);
handler.sendMessage(msg);
}
}).start();
}
});
}
}
- Post() : Code를 받아서 실행
Runnable에 코드를 담아서 전달하고, MainThread가 실행한다.
class ProgressRunnable implements Runnable {
int progress;
public ProgressRunnable(int progress) {
this.progress = progress;
}
@Override
public void run() {
progressBar.setProgress(progress);
tvMessageView.setText(" " + progress);
}
}
class DoneRunnable implements Runnable {
@Override
public void run() {
progressBar.setProgress(100);
tvMessageView.setText("done!");
}
}
new Thread(new Runnable() {
@Override
public void run() {
int count = 0;
while(count < 20) {
handler.post(new ProgressRunnable(count * 5));
count++;
}
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
}
handler.post(new DoneRunnable());
}
}).start();
* Handler 대신 사용할 수 있는 메소드
Activity.runOnUiThread(Runnable)
: Activity에서 MainThread로 Runnable를 실행한다.
* AsyncTask
: handler 대신 간단하게 실행할 수 있는 Background 작업
- MainThread job
onPreExcute : 시작
onProgressUpdate : 진행중 Progress update
(doInBackground에서 publishProgress로 작업진행상태를 표시할 수 있음)
onPostExcut : 종료시 실행
- New Thread
doInBackground : 작업진행
* Time thread back key 처리
// back key 처리
// app 종료 알림
private static final int MESSAGE_BACKKEY_TIMEOUT = 2;
private static final long TIMEOUT_BACKKEY_DELAY = 2000;
boolean isBackPressed = false;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case MESSAGE_BACKKEY_TIMEOUT:
isBackPressed = false;
break;
}
}
};
@Override
public void onBackPressed() {
if (!isBackPressed) {
isBackPressed = true;
Toast.makeText(this, "한번 더누르면 종료됨 ㅇㅇ", Toast.LENGTH_SHORT).show();
handler.sendEmptyMessageDelayed(MESSAGE_BACKKEY_TIMEOUT, TIMEOUT_BACKKEY_DELAY);
} else {
handler.removeMessage(MESSAGE_BACKKEY_TIMEOUT);
super.onBackPressed();
}
}
https://www.youtube.com/watch?v=qt-l0MIdhTM&list=PL9mhQYIlKEhc7o2HHixQi0PU2sQVerRW2&index=1
https://www.youtube.com/watch?v=1P9eV0ExuZ0&list=PL9mhQYIlKEhc7o2HHixQi0PU2sQVerRW2&index=2