2016-03-07

[Android] AsyncTask - UI 스레드에서는 시간이 오래 걸리는 일을 하면 안 된다

 안드로이드는 메인 스레드에서 UI와 관련된 일을 처리한다. 그래서 메인 스레드를 UI 스레드라고 부르기도 한다. 그런데 UI 스레드에서 오랫동안 CPU를 점유하는 일을 하게 되면, "Application Not Responding"이라는 메시지가 나온다. 이러면 앱에 대한 컨트롤을 잃게 되며, 응답할 때까지 기다리거나 강제종료할 수밖에 없다.
 이런 일을 방지하기 위해서는 새로운 스레드를 생성하여 다른 스레드에 시켜야 한다. 하지만 로우레벨의 스레드를 바로 사용하면 동기화하는 과정에서 쉽게 실수할 수 있으므로 실수 없이 쉽게 스레드를 사용할 수 있게 하려고 안드로이드는 AsyncTask라는 클래스를 지원한다.

 AsyncTask는 UI 스레드에서 잠시 동안 백그라운드로 일을 호출하고 싶을 때 사용된다. 잠시 동안이라는 것을 문서상으로는 should ideally be used for short operations (a few seconds at the most.)1)라고 표현하고 있다. 만약 길게 실행되는 일을 백그라운드에서 실행하고 싶으면 스레드를 직접 사용하거나 다른 방법을 이용해야 한다. 그 이유는 몇 가지 있다.
 대표적인 문제는, AsyncTaskActivity에 종속되지 않기 때문에, AsyncTask를 호출했던 Activity가 먼저 죽었을 경우 처리가 복잡해진다.
 또 다른 문제는 백그라운드 스레드를 점유해버린다는 것이다. AsyncTaskAsyncThread가 새로 만들어질 때마다 스레드를 생성하지 않는다. 고정된 크기의 스레드 풀이 있고 이 스레드 풀을 모든 AsyncTask가 공유한다. API 버전에 따라서 1개의 태스크만 실행될 수도 있고, 여러 개의 태스크가 병렬적으로 동시에 수행될 수도 있는데, 최신 버전은 1개만 실행되며 모든 태스크는 순차적으로 실행하게 되어 있다. 따라서 어떤 태스크가 데 시간이 오래 걸린다면 다른 태스크가 실행되지 못한다.

 AsyncTask를 사용하는 대략적인 과정은 다음과 같다. AsyncTask를 상속받는 클래스를 만들어서 필요한 함수를 오버라이드한다. 그 뒤 UI 스레드에서 AsyncTask를 상속한 클래스의 객체를 생성하여 execute 메소드를 실행시킨다.
 AsyncTask는 3개의 타입 파라미터를 받는다. 각각은 순서대로 Params, Progress, Result라고 부른다. Params는 태스크를 실행시킬 때 넘기는 파라미터의 타입이고, Progress는 UI 스레드에 태스크의 진행 상황을 넘기기 위해서 사용되는 파라미터의 타입이고, Result는 태스크의 결과를 UI 스레드에 넘길 때 사용되는 타입이다.

 AsyncTask를 상속받는 클래스는 반드시 doInBackground 함수를 구현해야 한다. 이 함수는 태스크를 백그라운드에서 실행시킬 일을 의미한다. 이 함수는 자동으로 백그라운드 스레드에서 실행되며, 수동으로 실행시켜서는 안 된다. 또한 이는 백그라운드 스레드에서 실행되기 때문에 UI를 수정하면 안 된다. 중간에 UI를 수정하고 싶으면 publishProgress 함수를 호출하여 UI 스레드에서 콜백이 실행되도록 해야 한다.  그 외에 필요에 따라서 onPreExecute, onPostExecute, onProgressUpdate, onCancelled 함수를 구현할 수 있다. 각각 태스크가 수행되기 전, 수행된 후, publishProgress 함수가 불렸을 때, 태스크가 취소됐을 때 UI 스레드에서 호출된다. 위의 상황에서 UI를 변경시키고자 할때는 위의 함수들을 구현해서 사용해야 한다.


1) http://developer.android.com/intl/ko/reference/android/os/AsyncTask.html

댓글 없음:

댓글 쓰기