안드로이드 - AsyncTask
1. 개요
스레드를 사용하면서 UI 객체에 접근하려면 핸들러를 통하면 된다. 하지만 Message 객체를 사용할 경우 코드가 길어진다는 문제가 생긴다.
AsyncTask는 하나의 클래스 안에 스레드로 동작하는 부분과 UI 객체에 접근하는 부분을 함께 넣을 수 있도록 합니다.
이 때문에 스레드를 사용하는 하나의 작업 단위가 AsyncTask라는 하나의 클래스로 만들어질 수 있다.
1. AsyncTask
- AsyncTask는 비 동기 처리를 위해 제공되는 클래스 이다.
- 개발자가 발생 시키는 쓰레드와 핸들러의 조합으로 쓰레드 운영 중 화면 처리가 가능했던 구조를 클래스로 제공하는 것이다.
- AsyncTask를 사용하면 개발자가 발생시키는 일반쓰레드와 화면 처리를 위해 MainThread를 이용하는것을 조합하여 작업이 가능하다.
2. 오버라이드 주요 메서드
1. onPreExeCute()
- doInBackground 메서드가 호출되기 전에 호출되는 메서드.
- Main Thread가 처리한다.
- 5초 이상의 작업을 하면 안되고, 화면 처리가 가능하다.
2. doInBackground()
- 일반 Thread에서 처리한다.
- 네트워크 작업 or 5초 이상 걸리는 작업을 이 메서드에서 처리한다.
3. onProgressUpdate()
- doInBackground 메서드에서 publishProgress 메서드를 호출하면 Main Thread가 처리하는 메서드.
- doInBackground 메서드 내에서 화면 처리가 필요할 때 사용한다.
4. onPostExcute()
- doInBackground 메서드 수행 완료 후 호출.
- Main Thread가 처리한다.
-> 스레드안에서 실행될 코드는 doInBackground() 에 넣어두고 UI에 접근할 코드는 나머지에 넣어둔다.
-> AsyncTask도 스레드를 실행하는 것과 같기 때문에 스레드 안에서 실행될 대부분의 코드는 doInBackground() 안에 들어가있게 되며 중간중간 화면에 표시하기 위한 코드 실행을 위해 onProgressUpdate()가 호출되는 것이다.
-> onProgressUpdate()는 doInBackground()안에서 publishProgress()가 호출될 때마다 자동으로 호출된다.
3. AsyncTaskClass 오버라이딩
1. inner class AsyncTaskClass : AsyncTask<Int, Long, String>()
// 제네릭 타입을 3개 지정해주어야 한다.
// 제네릭1) excute() 매개변수 타입
// 제네릭2) publishProgress() 매개변수 타입
// 제네릭3) doInBackground()의 반환 타입 이자 onPostExcute의 매개변수 타입
2. onCreate()에서 sync.excute() 호출로 AsyncTask 가동.
// execute()의 매개변수는 그대로 doInBackground()의 매개변수로 넘어간다.
3. onPreExecute()
4. doInBackground()
// 화면 처리가 필요하다면.....
5. doInBackground() 에서 publishProgress() 호출.
6. onProgressUpdate()
// publishProgress()의 매개변수가 전달됨 화면 처리.
7. doInBackground()의 작업이 끝나면 반환값을 onPostExecute()에 전달하며 종료.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener { view ->
var time = System.currentTimeMillis()
textView.text = "버튼 클릭 : ${time}"
}
var sync = AsyncTaskClass()
// 1. AsyncTask 가동. execute()의 매개변수는 그대로 doInBackground()의 매개변수로 넘어간다.
sync.execute(10, 20)
}
// 제네릭 타입을 3개 지정해주어야 한다.
// 제네릭1) excute() 매개변수 타입
// 제네릭2) publishProgress() 매개변수 타입
// 제네릭3) doInBackground()의 반환 타입 이자 onPostExcute의 매개변수 타입
inner class AsyncTaskClass : AsyncTask<Int, Long, String>() {
// doInBackground 메서드가 호출되기 전에 딱 한 번 호출되는 메서드. Main Thread가 처리한다.
override fun onPreExecute() {
super.onPreExecute()
textView2.text = " AsyncTask 가동 ";
}
// 일반 Thread에서 처리한다. 네트워크 작업 or 5초 이상 걸리는 작업을 이 메서드에서 처리한다.
// 1. execute()의 매개변수는 그대로 doInBackground()의 매개변수로 넘어간다.
override fun doInBackground(vararg params: Int?): String {
// 2.
// varag params에는 ?가 붙어서 NULL을 허용하지만, 정수 값을 뽑아낼거기 때문에 NULL을 허용하면 안되므로
// NULL을 허용하는 변수를 NULL을 허용하지 않는 변수에 넣고싶을 때는 느낌표2개(!!)을 붙여주면 된다.
var a1 = params[0]!!
var a2 = params[1]!!
for (idx in 0..9) {
SystemClock.sleep(100)
a1++
a2++
// 3.
// 이렇게하면 되긴하는데 WrongThread 경고가 뜬다. 안드로이드는 일반 쓰레드에서 화면 처리를 하면 경고를 보낸다. 따라서 좋은 코드가 아님.
//textView2.text = " ${idx} : ${a1}, ${a2}"
// 4.
// doInBackground() 에서 화면처리를 하려면 onProgressUpdate() 함수가 필요하고, 그 함수는 publishProgress()로 호출할 수 있다.
// publishProgress(varags 변수) 매개변수가 onProgressUpdate(varags 변수)로 전달된다. 값 여러개 전달하면 배열로 만들어져 전달된다.
// 메인쓰레드가 한가할 때 publishProgress()를 호출해준다.
var time = System.currentTimeMillis()
publishProgress(time)
}
return "지존현지"
}
// 4.
// doInBackground 메서드에서 publishProgress 메서드를 호출하면 Main Thread가 처리하는 메서드. doInBackground 메서드 내에서 화면 처리가 필요할 때 사용한다.
override fun onProgressUpdate(vararg values: Long?) {
super.onProgressUpdate(*values)
textView2.text = "Async : ${values[0]}"
}
// 5.
// doInBackground()의 반환 타입이 매개변수로 넘어온다.
// doInBackground 메서드 수행 완료 후 호출. MainThread가 처리한다.
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
textView2.text = result
}
}
4. varag 가변형 매개변수
- 가변형 매개변수. 값을 N개 넘겨주면 N개짜리 배열이 만들어져서 넘어간다.
https://developer.android.com/reference/android/os/AsyncTask.html