Android Developer

[Android] AsyncTask

졸려질려 2019. 8. 2. 00:22
반응형
20190731_AsyncTask.md

AsyncTask

Added in API level 3

public abstract class AsyncTask extends Object java.lang.Object -> android.os.AsyncTask<Params, Progress, Result>


Intro

UI Thread(Main Thread)

  • 어플리케이션의 프로세스를 실행하는 쓰레드
  • 화면 구성 담당 : Button, TextView 등의 UI 구성 요소를 생성 및 조작할 때 상호작용하는 쓰레드
  • 시간이 오래 걸리는 작업은 UI 쓰레드로부터 분리하여 별도의 쓰레드에서 실행 하는 것이 좋다.(UI쓰레드 지연 및 차단 방지)
  • Android UI 도구는 쓰레드로부터 세이프하지 않다. 따라서 UI 쓰레드가 아닌 쓰레드에서는 UI 구성요소를 조작하지 않는다.

AsyncTask

  • UI 쓰레드 를 적절하고 쉽게 사용할 수 있도록 해준다.
  • thread 나 handler 를 사용하지 않아도 백그라운드 작업 을 수행하고 UI 쓰레드에 결과를 출력 할 수 있다.
  • Thread 와 Handler 와 기능이 유사한 Helper class 이고 Generic Threading framework 를 구성하지 않는다.

    AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework.

  • 이상적으로는 짧은 시간에 동작이 수행 되어야한다.
    • 만약 긴 시간동안 쓰레드를 돌려야하면 java.util.concurrent 패키지에서 제공되는 다양한 API들을 사용하는 것을 권장한다.(Executor, ThreadPoolExecutor, FutureTask...)
  • 비동기 작업(Asynchronous Task)이란 백그라운드 쓰레드 에서 연산하고 UI 쓰레드 에서는 결과가 보여지는 것을 말한다.
  • 비동기 작업을 구성하는 것은 다음과 같다.
    • 제네릭 타입
      1. Params
      2. Progress
      3. Result
    • 수행 단계
      1. onPreExecute
      2. doInBackground
      3. onProgressUpdate
      4. onPostExecute

Usage

  • AsyncTask 는 반드시 서브 클래스 로 사용되어야한다. (Override 를 꼭 해야함.)
  • 예제 코드
    // AsyncTask 를 사용하기 위해서는 AsyncTask 를 상속받은 서브클래스를 객체로 만들어야한다. private class DownloadFilesTask extends AsyncTask<URL, Integer, Long>{ protected Long doInBackground(URL... urls){ int count = urls.length; long totalSize = 0; for(int i=0; i<count; i++){ totalSize += 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){ setProgressPercent(progress[0]); } protected void onPostExecute(Long result){ showDialog("Downloaded " + result + " bytes"); } }
    // AsyncTask 실행 new DownloadFilesTask().execute(url1, url2, url3);
    • 예제 코드만을 보았을 때 추측 해볼 수 있는 것은 다음과 같다.
      • AsyncTask<URL, Integer, Long> 에서 URL, Integer, Long 은 위에서 언급되었던 제네릭 타입 Params, Progress, Result 이다.
      • 또한 세 개의 제네릭 타입은 각각 doInBackground(), onProgressUpdate(), onPostExecute() 의 인자값 타입과 동일하다.
      • MainThread를 사용하는 MainActivity에서 DownloadFilesTask().execute(url1, url2, url3) 를 실행하면 execute 메소드의 인자값들은 doInBackground() 의 인자값으로 넘어가서 각 url 링크에서 다운받은 파일의 크기를 totalSize 에 합한다. 그리고 총 합쳐진 totalSize 값은 onPostExecute() 메소드의 인자값으로 넘겨진다.
      • onProgressUpdate() 메소드는 백그라운드에서 수행 중인 작업의 현재 상태를 출력해주는 메소드이다.
    • 그럼 이제 진짜 사실 은 무엇인지 보자.

AsyncTask's generic types

  • Intro에서 언급된 AsyncTask 의 제네릭 타입은 총 3가지이다.
    1. Params : AsyncTask 가 execute() 될 때 넘겨받는 인자값 의 타입
    2. Progress : 백그라운드에서 작업이 수행되는 동안 발행되는 진행 단위 의 타입
    3. Result : 백그라운드 작업의 결과값 의 타입
  • 3개의 제네릭 타입들을 모두 항상 사용하지 않는다. 사용하지 않을 때는 Void 로 타입값을 넣어준다.
    private class MyAsyncTask extends AsyncTask<Void, Void, Void> {...}

The 4 steps

  • 비동기 작업이 수행될 때, 해당 작업은 총 4단계를 거치게 된다.
    1. onPreExecute()
      • 비동기 작업이 이루어지기 전에 UI Thread 에서 호출되는 메소드이다.
      • 사용자 인터페이스에 Progress bar 를 표시하여 작업을 설정하는 데 사용된다.
    2. doInBackground(Params...)
      • onPreExecute() 가 끝나면 Background Thread 에서 호출되는 메소드이다.
      • 긴 시간이 필요한 백그라운드 연산을 수행하기 위해 사용된다.
      • 비동기 작업이 시작될 때 받는 인자값들이 전달되는 단계이다.
      • 연산의 결과값이 항상 return 되며 해당 값을 마지막 단계로 전달한다.
      • 진행 단위를 출력하고자 할 떄 publishProgress(Progress...) 를 사용한다.
      • 진행 단위 값들은 onProgressUpdate(Progress...) 단계의 UI Thread 에서 출력된다.
    3. onProgressUpdate(Progress)
      • publishProgress(Progress...) 이후에 UI Thread 에서 호출되는 단계이다.
      • 백그라운드 연산이 수행되는 동안 사용자 인터페이스에서 어떤 형태로든 진행 상황을 보여주기 위해 사용된다.
    4. onPostExecute(Result)
      • 백그라운드 연산이 끝난 후에 UI Thread 에서 호출되는 단계이다.
      • 백그라운드 연산의 결과값은 onPostExecute(Result) 의 인자값이 된다.

Cancelling a task

  • cancel(boolean) 메소드를 호출함으로써 언제든지 작업을 취소할 수 있다.
  • cancel(boolean) 메소드 호출은 이어서 true 를 반환하는 isCancelled() 를 호출한다.
  • isCancelled() 메소드가 호출되면 doInBackground() 에서 onPostExecute() 로 넘어가지 않고 onCacelled() 메소드로 넘어간다.
  • 이러한 취소 작업을 빨리 수행하기 위해서는 doInBackground() 메소드에서 주기적으로 isCancelled() 의 반환값을 확인 해줘야한다.

Threading rules

  • AsyncTask 클래스는 UI Thread 에서 로드 되어야한다. 이 점은 Build.VERSION_CODES.JELLY_BEAN 에서 자동으로 수행된다.
  • Task Instance 는 UI Thread 에서 생성 되어야한다.
  • execute(Params...) 는 UI Thread 에서 호출 되어야한다.
  • onPreExecute(), onPostExecute(Result), doInBackground(Params...). onProgressUpdate(Progress...) 를 수동적으로 호출하면 안된다.
  • AsyncTask 는 한 번만 실행될 수 있다.(두번째 실행이 시도되면 예외가 발생할 것이다.)

참고자료(출처)

  • AsyncTask https://developer.android.com/reference/android/os/AsyncTask#developer-guides https://itmining.tistory.com/7

  • UI Thread https://codetravel.tistory.com/9

반응형