Android
 Computer >> コンピューター >  >> プログラミング >> Android

【Android】AsyncTaskスレッドを安全に停止・キャンセルする方法を解説

この記事では、Androidアプリで実行中のAsyncTaskスレッドを停止(キャンセル)する方法を、実際に動作するサンプルコードとともにわかりやすく解説します。

ポイント:cancel()メソッドとisCancelled()メソッド

AsyncTaskを停止するには、cancel(boolean)メソッドを呼び出します。引数に「true」を渡すと、バックグラウンド処理を実行中のスレッドに対して割り込み(interrupt)が発生します。さらに、doInBackground()内ではisCancelled()メソッドを使ってタスクがキャンセルされたかどうかを判定し、ループを抜けるなど適切な終了処理を行うのが基本の流れです。

手順1:Android Studioで新規プロジェクトを作成する

Android Studioを起動し、「File」→「New Project」を選択して、必要な項目を入力して新しいプロジェクトを作成してください。

手順2:res/layout/activity_main.xml に以下のコードを追加する

ボタン2つ(タスク実行用・キャンセル用)と結果表示用のTextViewを配置したレイアウトです。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <Button
        android:id="@+id/btnDo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@id/btnCancel"
        android:layout_centerInParent="true"
        android:layout_marginBottom="25sp"
        android:text="Do AsyncTask" />
    <Button
        android:id="@+id/btnCancel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@id/textView"
        android:layout_centerInParent="true"
        android:layout_marginBottom="20dp"
        android:text="Cancel" />
    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textSize="20sp"
        android:gravity="center_horizontal" />
</RelativeLayout>

手順3:src/MainActivity.java に以下のコードを追加する

「Do AsyncTask」ボタンでタスクを開始し、「Cancel」ボタンで cancel(true) を呼び出して処理を中断します。doInBackground() 内では isCancelled() をチェックし、キャンセルされていればループを抜けます。

import android.graphics.Color;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
    private Button btnDo, btnCancel;
    private TextView textView;
    private AsyncTask myTask;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnDo = findViewById(R.id.btnDo);
        btnCancel = findViewById(R.id.btnCancel);
        textView = findViewById(R.id.textView);
        btnDo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                textView.setText("");
                myTask = new DownloadTask().execute("Task1",
                    "Task2", "Task3", "Task4", "Task5");
            }
        });
        btnCancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                myTask.cancel(true);
            }
        });
    }
    private class DownloadTask extends AsyncTask<String, Integer, List<String>> {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            textView.setTextColor(Color.BLUE);
            textView.setText(textView.getText() + "\n Starting Task....");
        }
        @Override
        protected List<String> doInBackground(String... tasks) {
            int count = tasks.length;
            List<String> taskList= new ArrayList<>(count);
            for(int i =0;i<count;i++){
                String currentTask = tasks[i];
                taskList.add(currentTask);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                publishProgress((int) (((i+1) / (float) count) * 100));
                if(isCancelled()){
                    break;
                }
            }
            return taskList;
        }
        @Override
        protected void onCancelled() {
            super.onCancelled();
            textView.setTextColor(Color.RED);
            textView.setText(textView.getText() + "\n Operation is cancelled..");
        }
        @Override
        protected void onProgressUpdate(Integer... progress) {
            super.onProgressUpdate(progress);
            textView.setText(textView.getText()+ "\n Completed:)" + progress[0] + "%");
        }
        @Override
        protected void onPostExecute(List<String> result) {
            super.onPostExecute(result);
            textView.setText(textView.getText() + "\n\n Done....");
            for (int i=0;i<result.size();i++){
                textView.setText(textView.getText() + "\n" +
                result.get(i));
            }
        }
    }
}

手順4:androidManifest.xml に以下のコードを追加する

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="https://schemas.android.com/apk/res/android"
    package="app.com.sample">
    <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スマートフォンをパソコンに接続していることを前提としています。Android Studioでプロジェクトのアクティビティファイルを開き、ツールバーの「Run」アイコンをクリックします。接続したモバイルデバイスを選択すると、端末に以下のような画面が表示されます。

【Android】AsyncTaskスレッドを安全に停止・キャンセルする方法を解説

【Android】AsyncTaskスレッドを安全に停止・キャンセルする方法を解説

補足:AsyncTaskは現在非推奨(Deprecated)

なお、AsyncTaskはAPIレベル30(Android 11)以降で非推奨(Deprecated)となっています。新規開発では、Kotlinコルーチン、ExecutorService、HandlerThread、WorkManagerなどの代替手段の利用が推奨されます。ただし、既存コードの保守やレガシーアプリの改修では依然として登場するため、本記事のように cancel(true) と isCancelled() を組み合わせた正しいキャンセル処理の理解は重要です。

  1. AndroidでJSONを解析する方法を徹底解説!初心者向けステップバイステップガイド

    はじめに この記事では、AndroidアプリでJSONデータを解析(パース)する方法を、実際のコード例とともにわかりやすく解説します。JSONはWeb APIなどで広く利用されているデータ形式であり、Android開発においてその扱い方をマスターすることは非常に重要です。 ステップ1:新規プロジェクトの作成 まず、Android Studioで新しいプロジェクトを作成します。メニューから「File」→「New Project」を選択し、必要な項目をすべて入力してプロジェクトを作成しましょう。 ステップ2:レイアウトファイルの作成 次に、res/layout/activity_main.xm

  2. 【Android】TextViewでテキストを両端揃え(ジャスティファイ)表示する方法

    概要 本記事では、AndroidアプリのTextViewに表示するテキストを両端揃え(ジャスティファイ)にする方法を、サンプルコードとともにわかりやすく解説します。 TextViewで両端揃えを実現するには、android:justificationMode=inter_wordを指定するだけです。この機能はAndroid 8.0(APIレベル26)以降で有効になるため、それ以前のOSバージョンでは無視される点に注意してください。 手順1:新規プロジェクトを作成する まず、Android Studioを起動し、メニューから「File」⇒「New Project」を選択します。必要な項目をす