Android에서의 비동기 작업 처리: AsyncTask 활용법

AsyncTask를 통한 비동기 처리 이해

Android는 4.0 이후부터 메인 스레드에서 네트워크 요청을 금지하면서, 사용자 인터페이스의 응답성을 보장하기 위해 비동기 처리가 필수적으로 요구됩니다. 이에 따라 개발자는 주 스레드에서 무거운 작업(예: 이미지 다운로드, 서버 요청)을 수행하지 않도록 해야 하며, 이를 위해 AsyncTask 클래스가 제공됩니다.

AsyncTask<Params, Progress, Result>는 비동기 작업을 쉽게 구현할 수 있도록 도와주는 추상 클래스입니다. 세 가지 타입 매개변수는 각각 다음과 같은 의미를 가집니다:

  • Params: 백그라운드 작업에 전달할 입력 데이터 타입 (예: 문자열 형식의 URL)
  • Progress: 진행 상황을 전달할 데이터 타입 (예: 정수형 진행률)
  • Result: 작업 완료 후 반환되는 결과 타입 (예: 이미지 데이터인 Bitmap)

핵심 콜백 메서드 순서

  1. onPreExecute(): 백그라운드 작업 시작 전에 호출되며, 초기 설정이나 로딩 애니메이션 표시 등에 사용됩니다.
  2. doInBackground(Params...): 실제로 백그라운드에서 실행되는 메서드이며, 네트워크 요청, 파일 처리 등의 작업을 수행합니다. 이 메서드 내부에서 publishProgress()를 호출하면 onProgressUpdate()가 트리거됩니다.
  3. onProgressUpdate(Progress...): publishProgress()를 통해 전달된 값에 따라 실시간으로 진행 상태를 업데이트할 때 호출됩니다.
  4. 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" />

네트워크 접근을 위해 반드시 해당 권한을 선언해야 합니다.

주의사항 및 한계

  • AsyncTaskAPI 11 이상에서 단일 스레드 풀을 사용하며, 동시에 여러 작업을 실행할 경우 큐에 대기하게 됩니다.
  • 작업이 너무 오래 걸리거나, 화면 회전 시 Activity가 재생성되면 AsyncTask가 정상적으로 완료되지 않을 수 있습니다.
  • 현재는 WorkManagerCoroutine 등 더 현대적인 비동기 처리 기법이 권장되고 있으나, AsyncTask는 여전히 간단한 작업에 유용합니다.

이 예제를 통해 AsyncTask의 동작 흐름과 실제 개발에서의 활용 방식을 이해할 수 있습니다.

태그: Android AsyncTask 비동기 처리 이미지 다운로드 네트워크 요청

5월 31일 15:30에 게시됨