본문 바로가기
프로그래밍 놀이터/안드로이드, Java

Efficient Android Threading #8 AsyncTask 로 백그라운드 태스크를 UI 스레드에 묶기

by 돼지왕왕돼지 2018. 3. 24.

Efficient Android Threading #8 AsyncTask 로 백그라운드 태스크를 UI 스레드에 묶기


이 글은 Efficient Android Threading 의 일부 내용만 발췌한 내용입니다.

자세한 내용은 책을 구입해서 보세용.

128개 태스크, 2*n+1, api level 13, api11, Asynctask, asynctask priority, asynctask 구현, AsyncTask 의 대안, asynctask 재사용, AsyncTask.SERIAL_EXECUTOR, AsyncTask.THREAD_POOL_EXECUTOR, Callback, callback thread, cancel, cpu 코어 수, custom executor, doinbackground, Efficient Android Threading #8 AsyncTask 로 백그라운드 태스크를 UI 스레드에 묶기, execute, executeOnExecutor, executor, executor framework, finished, getstatus, handlerthread, illegalstateexception, INTERRUPT, n+1, onCancelled, onpostexecute, onpreexecute, onprogressupdate, pending, Process.THREAD_PRIORITY_BACKGROUND, Runnable, Running, serial executor 기본, SERIAL_EXECUTOR, targetsdkversion, thread, THREAD_POOL_EXECUTOR, True, UI Thread, 각기 다른 스레드, 다양한 플랫폼 버전, 백그라운드 태스크 실행, 상태, 생성과 시작, 스레드, 스레드 안전, 앱 전역 실행, 자원 효율적, 작업 큐, 재사용, 재실행, 젤리빈, 지역 서비스, 첫번째 asynctask, 취소, 커스텀 실행, 코어 스레드, 킷캣, 태스크 방해, 평범한 구현

10.1. 기본 사항


-

AsyncTask 는 실행이 완료되면 다시 실행할 수 없다.

즉, execute 메서드는 일회성의 동작이고 스레드의 동작처럼 AsyncTask 인스턴스마다 오직 한 번만 호출할 수 있다.



-

doInBackground 작업이 끝나면 onPostExecute 혹은 onCancelled 둘 중 하나만 수행된다.




** 10.1.1 생성과 시작


-

AsyncTask 의 기본 생성자는 UI 스레드에서 호출되어야 한다.

젤리빈 이전의 플랫폼에서 UI 스레드가 아닌 다른 스레드가 AsyncTask 를 생성하면 콜백은 올바른 스레드에서 일어나지 않을 수 있다.

AsyncTask 를 생성한 스레드에 따라 onProgressUpdate, onPostExecute, onCancelled 콜백이 어떤 스레드에서 실행될지 결정된다.


실제로 앱 프로세스에서 첫 번째로 생성된 AsyncTask 는 앱 내의 연이은 모든 AsyncTask 구현에 대한 콜백 스레드를 제어한다.

콜백 스레드는 앱 수명마다 한 번만 설정된다.

젤리빈부터 AsyncTask 는 UI 스레드에서 앱 시작 시 클래스 로드되어 콜백이 UI 스레드에서 일어남을 보장한다.



-

execute 메서드는 UI 스레드에서 호출해야 한다. 그렇지 않으면 onPreExecute 콜백이 UI 스레드에서 일어나지 않는다.



-

실행은 한 번만 호출되는 일회성 테스크이며, 두 번 이상 호출하면 IllegalStateException 이 발생한다.




** 10.1.2. 취소


-

AsyncTask.cancel(true) 에서 boolean flag 값은 isCancelled flag 만 켤 것이냐, interrupt 도 걸 것이냐를 결정한다.

true 이면 interrupt 까지 건다.




** 10.1.3. 상태


-

AsyncTask.getStatus() 를 통해 얻는다.


PENDING

    AsyncTask 인스턴스가 생성되었지만, execute 가 호출되지 않음.


RUNNING

    execute 가 호출되었음, onPostExecute, onCancelled 함수 처리가 끝날 때까지 이 상태임


FINISHED

    onPostExecute 또는 onCancelled 메소드 처리가 다 끝난 상태.





10.2. AsyncTask 구현


** 10.2.1. 예제 : 이미지 다운로드







10.3. 백그라운드 태스크 실행


-

AsyncTask.execute(Runnable) 함수도 있는데, 이 녀석은 API 11 에서 추가되었으며, AsyncTask 내부 실행 환경에서 처리되지만, 스레드 간의 통신을 위해 메시지 전달을 사용하지 않는다.

onPreExecute, onPostExecute, onCancelled 는 호출되지 않고 진행 상태도 표시되지 않는다.



-

asyncTask.executeOnExecutor 역시 API 11 에서 추가되었으며, 이 메서드는 내부 실행 환경을 활용하거나 커스텀 Executor 를 사용한다.

Executor 인수는 다음 중 하나가 될 수 있다.


AsyncTask.THREAD_POOL_EXECUTOR

    테스크들이 동시 처리된다. 킷캣에서 스레드 풀 크기는 사용 가능한 CPU 코어 수에 기초한다.

    N+1 개의 코어 스레드와 최대 2*N + 1 개의 스레드, 작업 큐는 128개의 태스크를 보유할 수 있다.


AsyncTask.SERIAL_EXECUTOR

    스레드 안전한 테스크 실행을 보장한다.

    자신의 스레드를 포함하지 않고, 대신 실행을 위해 THREAD_POOL_EXECUTOR 에 의지한다.

    무제한 큐에 태스크를 저장하고 순차적으로 실행되도록 각 태스크를 THREAD_POOL_EXECUTOR 로 전달한다.

    즉 태스크들은 스레드 풀의 각기 다른 스레드에서 실행될 수 있지만, 순차적 실행은 보장한다.


커스텀 executor 도 설정 가능하다.



-

AsyncTask 는 UI 스레드에 덜 방해되도록 Process.THREAD_PRIORITY_BACKGROUND 로 낮춰진다.




** 10.3.1. 앱 전역 실행


-

모든 AsyncTask 인스턴스는 전역 실행을 공유하기 때문에 실행 환경에 따라 인스턴스끼리 서로 영향을 줄 수 있다.


SERIAL_EXECUTOR

    API Level 13  이상의 execute 에서는 기본이 SERIAL 이다.


THREAD_POOL_EXECUTOR

    API Level 13 이전의 execute 에서의 기본 동작이었다. ( 3 이하는 순차였지만 무시.. )


이 동작은 targetSdkVersion 의 버전에 의존한다.




** 10.3.2. 다양한 플랫폼 버전에서 실행




** 10.3.3. 커스텀 실행





10.4. AsyncTask 의 대안


** 10.4.1. AsyncTask 가 너무 평범하게 구현된 경우


-

doInBackground 만 구현한 경우에는 Thread 나 HandlerThread 를 사용하는 것이 좋다.




** 10.4.2. 루퍼가 필요한 백그라운드 태스크




** 10.4.3. 지역 서비스


-

서비스는 다음 중 하나의 대안 해결책을 사용하는 것이 좋다.


Thread, Executor Framework, HandlerThread, 커스텀 실행자를 가진 AsyncTask




** 10.4.4. execute(Runnable) 사용


-

장점 : 이미 존재하는 AsyncTask 내부 스레드 풀에서 태스크가 실행되므로 자원 효율적이다.

단점 : 태스크는 항상 앱 전역 실행 환경에서 실행하고 다른 태스크를 방해할 수 있다.






댓글0