평범한 개발자 행복한 가족, 패밀리그램

개발/안드로이드

AsyncTask 에 대하여 #1. 간단한 설명

패밀리그램 2016. 12. 5. 18:35

안드로이드 App개발에서 빼 놓을 수 없는 AsyncTask에 대한 포스팅을 이번에 해보려고한다.


AsyncTask에 대해서는 워낙 많이 사용되고 비동기 처리에서 모르면 안돼는 것이니 자세한 설명은 생략하겠다.


AsyncTask에 대하여 



1. AsyncTask의 소속 패키지


안드로이드 Framework 소스를 볼 때 패키지에 대해서도 한번 관심을 갖어주어야한다.

  - android.os.AsyncTask


AsyncTask 의 패키지는 android.os 이다. 패키지가 직관적이지 않은가?

android 의  os와 관련있는 패키지라는 것이다.


그렇다면 왜 OS와 관련이있을까 ? 


답변은 간단하다, AsyncTask의 스케쥴링을 OS에서 해주기 때문이다.

Thread를 사용하면 Thread Pool을 만들어 관리가 필요한데, 그런거 필요없다.

OS, 즉 안드로이드 Framework에서 제공하는 ThreadPool을 사용하면 정말 관리가 쉽다.


Framework에서 제공하는 ThreadPool은 #2에서 확인해보도록 하고 AsyncTask를 사용하는 방법 부터 확인해보자


2. Google 기본 예제


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 private class DownloadFilesTask extends AsyncTask<String, Integer, Long> {
 
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            // doInBackground 이전에 호출, 
            // 만약 ThreadPool에 들어가 대기상태라면 호출됨
        }
 
        protected Long doInBackground(String... urls) {
            int count = urls.length;
            long totalSize = 0;
            for (int i = 0; i < count; i++) {
                totalSize += 0;//Downloader.downloadFile(urls[i]);
                publishProgress((int) ((i / (float) count) * 100));
                // Escape early if cancel() is called
                if (isCancelled()) break;
            }
            return totalSize;
        }
 
        protected void onProgressUpdate(Integer... progress) {
            // Main Thread 호출
            //publishProgress 에 의해 호출됨
        }
 
        protected void onPostExecute(Long result) {
            // Main Thread 호출
            // doInBackground 완료 후 호출
        }
 
        @Override
        protected void onCancelled(Long aLong) {
            // Main Thread 호출
            // AsyncTask 가 cancel(true) 호출되어 취소되면 호출됨 
            // onPostExcuete는 호출되지 않는다
        }
    }
cs



<String, Integer, Long>은 Java Generic 인데 자세한건 위 Google link 에서 확인하고 따로 공부해보는 것을 추천한다.


<String, Integer, Long> 앞에서 부터 순서대로 doInBackground(), onProgressUpdate(), onPostExecute()로 전달되는 인자이다.


여기서 doInBackground의 인자에는 특이하게 ... 이 붙어있는데 이것은 자바에서 사용되는 문법이다.


해당 함수를 사용 할 때 같은 형태의 복수의 인자를 넣을 수 있으며, 함수로 들어오는 인자는 배열로 들어온다.


예를 들어 execute("A", "B", "C", ....) 로  AsyncTask를 동작 시킨다면, doInBackground의 String... 은 배열로 들어온다는 뜻이다

String... 의 인자가  {"A", "B", "C"}의 배열이란 뜻이다.


위 설명을 바탕으로 DownloadFilesTask라는 클래스는 여러 개의 다운로드가능 한 URLs를 받아 다운로드 받는 동작을 할 것이다.

(구현은 안되었지만, 그렇게 추측 할 수 있다는 말이다.)


또한 위 소스는 Google Developer Guide에서 복사한 것이다. 일부 부분은 주석처리하고, 나머지 코드에 코멘트를 추가한 소스이다.


3. 동작 순서


DownloadFileTask라는 객체를 생성하여 아래와 같이 실행했다고 했을 때 어떤 순서대로 동작하는지 확인해보자.


1
2
    DownloadFilesTask task = new DownloadFilesTask();
    task.execute("http://....");
cs



1. task를 생성하여 execute 가 호출 되는 순간 task는 Thread Pool에 들어가게되고 onPreExecute 가 호출 된다.

2. onPreExcecute 호출 후 OS 스케쥴링에 의해 해당 task의 차례가 되면 doInBackground가 호출된다.

3. doInBackgound 내 에서 publishProgress 를 호출 하면 onProgressUpdate가 호출된다.

4. doInBackgound가 정상적으로 완료되면 onPostExecute가 호출된다.

5. 만약 도중에 강제로 취소되면 onCancelled가 호출된다.


간단한 동작은 위 순서와 같다.


위 코드에 보면 코멘트에 MainThread라고 추가된 부분이 있는데 이 부분은 말 그대로 MainThread에서 호출된다고 보면된다.


Thread와 MainThread 를 간단하게 설명하자면 MainThread는 UI 를 동작시키는 Thread라고 생각하면된다.


안드로이드 OS에서는 Thread에서 View를 조작하는 것을 허용하지 않는다.

그렇기 때문에 Thread를 이용하여 View를 업데이트 할 때는 Thread 내에서 MainLooper를 호출하거나 Acitivty UI Thread를 호출하여

View를 업데이트 하는 방법도 있지만, 스케쥴링이 어렵기 때문에  OS에서 관래해주는 AsyncTask를 사용하는 것을 추천한다.


onPreExecute에서는 Thread 동작 전의 UI 를 업데이트 하면 되고

onProgressUpdate 에서는 doInBackground에서 publishProgress에 의해 업데이트 되고 있는 상태를 업데이트 하면된다.

동작이 완료되면 onPostExecute에서 UI 처리를 해주면 되는 것이다.


어렵기도 하지만, 곰곰히 생각해 보면 그리 어렵지 않고 쉽다.


다음 포스팅에는 AsyncTask의 스케쥴링에 대해 간단하게 알아 보겠다.


AsyncTask 에 대하여 #2. 스케쥴링 ThreadPool



반응형