Computer >> 컴퓨터 >  >> 프로그래밍 >> Android

안드로이드에서 실행 중인 AsyncTask를 취소하는 방법

AsyncTask란 무엇인가?

본격적인 예제에 들어가기 전에, 안드로이드에서 AsyncTask가 어떤 역할을 하는지 먼저 알아야 합니다. AsyncTask는 백그라운드 스레드에서 작업을 수행하고, 그 결과를 메인 스레드(UI 스레드)에 업데이트하는 클래스입니다. 백그라운드 작업이 진행되는 동안 사용자는 다음 코드를 사용해 작업을 취소할 수 있습니다.

AsynTaskExample mAsyncTask = new AsyncTaskExample();
mAsyncTask.cancel(true);

이 예제는 안드로이드에서 실행 중인 AsyncTask를 취소하는 방법을 단계별로 설명합니다.

1단계 − 새 프로젝트 생성

Android Studio에서 File ⇒ New Project로 이동한 후, 새 프로젝트 생성에 필요한 정보를 모두 입력하여 프로젝트를 만듭니다.

2단계 − 레이아웃 파일 작성

res/layout/activity_main.xml에 다음 코드를 추가합니다.

<?xml version = "1.0" encoding = "utf-8"?>
<LinearLayout xmlns:android = "https://schemas.android.com/apk/res/android"
    xmlns:tools = "https://schemas.android.com/tools"
    android:id = "@+id/rootview"
    android:layout_width = "match_parent"
    android:layout_height = "match_parent"
    android:orientation = "vertical"
    android:background = "#c1c1c1"
    android:gravity = "center_horizontal"
    tools:context = ".MainActivity">
    <Button
        android:id = "@+id/asyncTask"
        android:text = "Download"
        android:layout_width = "wrap_content"
        android:layout_height = "wrap_content" />
    <ImageView
        android:id = "@+id/image"
        android:layout_width = "300dp"
        android:layout_height = "300dp" />
</LinearLayout>

위 코드에서는 버튼을 클릭하면 인터넷에서 이미지를 다운로드하여 ImageView에 표시하도록 구성했습니다.

3단계 − MainActivity.java 작성

src/MainActivity.java에 다음 코드를 추가합니다.

package com.example.andy.myapplication;

import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class MainActivity extends AppCompatActivity {
    URL ImageUrl = null;
    InputStream is = null;
    Bitmap bmImg = null;
    ImageView imageView = null;
    AsyncTaskExample asyncTask = null;
    ProgressDialog p;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = findViewById(R.id.asyncTask);
        imageView = findViewById(R.id.image);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                asyncTask = new AsyncTaskExample();
                asyncTask.execute("https://www.tutorialspoint.com/images/tp-logo-diamond.png");
            }
        });
    }

    private class AsyncTaskExample extends AsyncTask<String, Void, Bitmap> {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            p = new ProgressDialog(MainActivity.this);
            p.setMessage("Please wait...It is downloading");
            p.setIndeterminate(true);
            p.setCancelable(true);
            p.setOnCancelListener(new DialogInterface.OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dialog) {
                    asyncTask.cancel(true);
                    Toast.makeText(MainActivity.this, "AsyncTask is stopped", Toast.LENGTH_LONG).show();
                }
            });
            p.show();
        }

        @Override
        protected Bitmap doInBackground(String... strings) {
            try {
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                ImageUrl = new URL(strings[0]);
                HttpURLConnection conn = (HttpURLConnection) ImageUrl.openConnection();
                conn.setDoInput(true);
                conn.connect();
                is = conn.getInputStream();
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inPreferredConfig = Bitmap.Config.RGB_565;
                bmImg = BitmapFactory.decodeStream(is, null, options);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return bmImg;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            if (imageView != null) {
                p.hide();
                imageView.setImageBitmap(bitmap);
            } else {
                p.show();
            }
        }
    }
}

위 코드의 핵심은 ProgressDialog에 취소 리스너(setOnCancelListener)를 등록한 부분입니다. 사용자가 다이얼로그를 취소하면 asyncTask.cancel(true)가 호출되어 백그라운드 작업이 중단됩니다.

4단계 − 매니페스트 설정

manifest.xml에 다음 코드를 추가합니다.

<?xml version = "1.0" encoding = "utf-8"?>
<manifest xmlns:android = "https://schemas.android.com/apk/res/android"
    package = "com.example.andy.myapplication">
    <uses-permission android:name = "android.permission.INTERNET"/>
    <application
        android:allowBackup = "true"
        android:icon = "@mipmap/ic_launcher"
        android:label = "@string/app_name"
        android:roundIcon = "@mipmap/ic_launcher_round"
        android:supportsRtl = "true"
        android:theme = "@style/AppTheme">
        <activity android:name = ".MainActivity">
            <intent-filter>
                <action android:name = "android.intent.action.MAIN" />
                <category android:name = "android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

위 코드에서는 인터넷에서 이미지를 가져올 수 있도록 인터넷 권한(android.permission.INTERNET)을 부여했습니다.

애플리케이션 실행 및 결과 확인

애플리케이션을 실행해 보겠습니다. 실제 안드로이드 모바일 기기가 컴퓨터에 연결되어 있다고 가정합니다. Android Studio에서 앱을 실행하려면 프로젝트의 액티비티 파일 중 하나를 연 뒤 툴바의 Run 아이콘을 클릭하세요. 목록에서 자신의 모바일 기기를 선택하면, 기기 화면에 아래와 같은 기본 화면이 표시됩니다.

안드로이드에서 실행 중인 AsyncTask를 취소하는 방법

버튼을 클릭하면 프로그레스바가 시작됩니다. 이때 프로그레스바가 아닌 다른 영역을 클릭하면 다음과 같은 화면이 나타납니다.

안드로이드에서 실행 중인 AsyncTask를 취소하는 방법

위 화면은 AsyncTask가 중지되었음을 명확하게 보여줍니다.

안드로이드에서 실행 중인 AsyncTask를 취소하는 방법

반대로 AsyncTask를 중지하지 않으면, 위 화면과 같이 이미지가 정상적으로 다운로드되어 표시됩니다.

추가 팁

cancel(true)를 호출한다고 해서 doInBackground() 내부의 작업이 즉시 중단되는 것은 아닙니다. 오래 걸리는 반복 작업이라면 루프 안에서 isCancelled()를 주기적으로 확인하여, 취소 요청 시 작업을 빠르게 종료하도록 구현하는 것이 좋습니다. 또한 AsyncTask는 현재 deprecated된 API이므로, 새 프로젝트에서는 Kotlin 코루틴(Coroutines)이나 WorkManager를 사용하는 것을 권장합니다.