❮
7.1: AsyncTask and AsyncTaskLoader(1 AsyncTask)
20171120
https://google-developer-training.gitbooks.io/android-developer-fundamentals-course-concepts/content/en/Unit%203/71c_asynctask_and_asynctaskloader_md.html
(Android Developer Fundamentals Course 7.1)
Contents:
안드로이드에서 백그라운드 작업을 하는 방법은 2가지가 있습니다.
1. AsyncTask 클래스를 이용하는 법
2. Loader 프레임워크를 이용하는 법
대부분의 상황에서 Loader 프레임워크를 이용하게 된다.
그러나 AsyncTask 클래스가 어떻게 동작하는 지를 알아두어야 둘 중 필요한 것을 상황에 맞게 선택할 수 있다.
The UI thread
- UI thread는 적절한 UI 위젯에 이벤트를 전달하는 역할
- 앱이 Android UI 툴킷의 구성요소와 상호작용하는 곳
<중요한 2가지 규칙>
1. UI 스레드를 차단하면 안된다.
2. UI 작업은 UI 스레드에서만 해야한다.
UI 스레드를 5초 이상 차단하면 응답하지 않는 프로그램으로 처리되어 종료될 수 있다.
--> ui 화면에 대해서 16ms 미만으로 작업을 처리한다. // 오래 걸리는 작업은 백그라운드에서 처리한다.
UI를 조작하기 위해서 백그라운드 스레드를 사용하면 안된다. (스레드-안전하지 않음)
AsyncTask 클래스
AsyncTask 사용법
AsyncTask
클래스를 사용하려면, AsyncTask의 서브클래스를 정의하고 doInBackground(Params...) 메소드를 오버라이드 해야한다. (보통 onPostExecute(Result) 메소드도 오버라이드하게 된다.)
AsyncTask 매개변수들
- "Params" 은
doInBackground()
메소드에 전달될 매개변수의 타입을 배열로 지정한다.
- "Progress" 는 백그라운드 스레드에서
publishProgress()
에 전달될 매개변수의 타입을 지정한다. 이 매개변수들은 메인 스레드에 있는 onProgressUpdate()에도 전달되게 된다.
- "Result" 는
doInBackground()
메소드가 리턴할 데이터의 타입을 지정해준다. 이 매개변수는 자동으로 메인 메소드에 있는 onPostExecute()
에도 전달되게 된다.
매개변수의 타입을 각각 따로 지정해주어야 하고, 사용하지 않는 매개변수인 경우에는 Void로 남겨두어야 한다. For example:
public class MyAsyncTask extends AsyncTask <String, Void, Bitmap>{}
- "Params" 매개변수의 타입은 String 이다.
MyAsyncTask
는 하나 이상의 문자열을 매개변수로 doInBackground()에 전달하게 된다. 예를 들어 쿼리를 하는데 이용할 수 있다.
- "Progress" 매개변수는 Void로 지정되어 있다. 즉, the
publishProgress()
or onProgressUpdate()
methods 에는 매개변수를 사용하지 않게 된다.
- "Result" 매개변수의 타입은
Bitmap
이다.
MyAsyncTask
클래스는 doInbackground()
메소드에서 비트맵을 리턴하고, 이것을 onPostExecute()에 전달한다.
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");
}
}
doInBackground()
는 컨텐츠를 다운로드한다. (오래 걸리는 작업). 여기서는 for 루프에서 파일의 다운로드가 어느 정도 되었는지 퍼센티지로 계산하고, publishProgress()에 전달한다. for 루프에서 isCancelled()를 이용해서 작업이 취소되었는지를 체크한다. (무한루프 방지)
onProgressUpdate()
는 퍼센트 진행상황을 업데이트 해준다. publishProgress()
메소드는 doInBackground()
안에서 계속 호출되고, 퍼센트로 진행상황을 업데이트해준다.
doInBackground()
다운로드 받은 바이트의 전체 수를 계산해주고 리턴한다. onPostExecute()
는 리턴받은 변수를 onPostExecute()
로 전달한다 . onPostExecute()에서는 대화상자에 바이트 수를 나타낸다.
AsyncTask 작동
new DownloadFilesTask().execute(url1, url2, url3);
AsyncTask 취소하기
- 이미 취소된 경우에는 중복해서 취소할 수 없으므로 false를 리턴한다. 이외의 경우에는 true 리턴.
- 작업이 취소됐는지 확인하기 위해서, doInBackground(Object[]) 에서isCancelled()의 리턴값을 주기적으로 확인해야한다.
- AsyncTask 작업이 취소되면, onPostExecute()는 호출되지 않는다. 대신, onCancelled(Object)가 호출된다. (디폴트로는 그저 무시하는 걸로 구현되어 있다.)
- cancel() 이 진행중인 작업을 인터럽트하게 하려면 mayInterruptIfRunning 에 true를 전달해야한다.
AsyncTask 클래스의 한계
몇몇 경우에 실용적이지 못하다.
1. device 설정을 바꾸면 문제를 일으킨다.
AsyncTask가 작동하는 도중에 디바이스 설정을 바꾸면(스크린회전 등), AsyncTask 가 만들어진 액티비티가 파괴되고 다시 만들어진다. AsyncTask는 새로 만들어진 액티비티에 접근할 수 없다.
2. 오래된 AsyncTask 객체가 계속 남아, 어플이 메모리부족이나 충돌을 일으킬 수 있다.
AsyncTask를 만든 액티비티가 파괴될 때 AsyncTask가 같이 파괴되지 않는다.
- 짧고 인터럽트할 수 있는 작업.
- UI나 user에게 다시 무언가를 돌려줄 필요가 없는 작업
- 완료되지 않은 채로 남아있어도 되는 중요도가 낮은 작업