AsyncTask를 통한 비동기 처리 이해
Android는 4.0 이후부터 메인 스레드에서 네트워크 요청을 금지하면서, 사용자 인터페이스의 응답성을 보장하기 위해 비동기 처리가 필수적으로 요구됩니다. 이에 따라 개발자는 주 스레드에서 무거운 작업(예: 이미지 다운로드, 서버 요청)을 수행하지 않도록 해야 하며, 이를 위해 AsyncTask 클래스가 제공됩니다.
AsyncTask<Params, Progress, Result>는 비동기 작업을 쉽게 구현할 수 있도록 도와주는 추상 클래스입니다. 세 가지 타입 매개변수는 각각 다음과 같은 의미를 가집니다:
- Params: 백그라운드 작업에 전달할 입력 데이터 타입 (예: 문자열 형식의 URL)
- Progress: 진행 상황을 전달할 데이터 타입 (예: 정수형 진행률)
- Result: 작업 완료 후 반환되는 결과 타입 (예: 이미지 데이터인
Bitmap)
핵심 콜백 메서드 순서
onPreExecute(): 백그라운드 작업 시작 전에 호출되며, 초기 설정이나 로딩 애니메이션 표시 등에 사용됩니다.doInBackground(Params...): 실제로 백그라운드에서 실행되는 메서드이며, 네트워크 요청, 파일 처리 등의 작업을 수행합니다. 이 메서드 내부에서publishProgress()를 호출하면onProgressUpdate()가 트리거됩니다.onProgressUpdate(Progress...):publishProgress()를 통해 전달된 값에 따라 실시간으로 진행 상태를 업데이트할 때 호출됩니다.onPostExecute(Result):doInBackground()가 종료되면 자동으로 실행되며, 결과 데이터를 메인 스레드에서 UI 업데이트에 사용할 수 있습니다.
실습 예제: 웹 이미지 다운로드
다음은 AsyncTask를 이용해 원격 이미지를 다운로드하고 ImageView에 표시하는 예제입니다.
1. 레이아웃 구성 (activity_main.xml)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="visible" />
</RelativeLayout>
2. Activity 코드 (MainActivity.java)
public class MainActivity extends AppCompatActivity {
private ImageView imageView;
private ProgressBar progressBar;
private static final String IMAGE_URL = "https://www.baidu.com/img/bdlogo.png";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = findViewById(R.id.imageView);
progressBar = findViewById(R.id.progressBar);
new ImageDownloadTask().execute(IMAGE_URL);
}
private class ImageDownloadTask extends AsyncTask<String, Integer, Bitmap> {
@Override
protected void onPreExecute() {
super.onPreExecute();
progressBar.setVisibility(View.VISIBLE);
imageView.setImageResource(android.R.color.transparent);
}
@Override
protected Bitmap doInBackground(String... urls) {
String urlStr = urls[0];
Bitmap bitmap = null;
try {
URL url = new URL(urlStr);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
connection.setRequestMethod("GET");
InputStream inputStream = connection.getInputStream();
BufferedInputStream bufferedStream = new BufferedInputStream(inputStream);
bitmap = BitmapFactory.decodeStream(bufferedStream);
bufferedStream.close();
connection.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// 진행률 업데이트 가능 (예: 프로그레스바 갱신)
}
@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
if (result != null) {
imageView.setImageBitmap(result);
} else {
imageView.setImageResource(R.drawable.error_image);
}
progressBar.setVisibility(View.GONE);
}
}
}
3. 권한 추가 (AndroidManifest.xml)
<uses-permission android:name="android.permission.INTERNET" />
네트워크 접근을 위해 반드시 해당 권한을 선언해야 합니다.
주의사항 및 한계
AsyncTask는 API 11 이상에서 단일 스레드 풀을 사용하며, 동시에 여러 작업을 실행할 경우 큐에 대기하게 됩니다.- 작업이 너무 오래 걸리거나, 화면 회전 시
Activity가 재생성되면AsyncTask가 정상적으로 완료되지 않을 수 있습니다. - 현재는
WorkManager나Coroutine등 더 현대적인 비동기 처리 기법이 권장되고 있으나,AsyncTask는 여전히 간단한 작업에 유용합니다.
이 예제를 통해 AsyncTask의 동작 흐름과 실제 개발에서의 활용 방식을 이해할 수 있습니다.