프로그래밍/Android

Android Thread Handler

showmiso 2019. 4. 17. 17:36

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