Hướng dẫn này trình bày cách hủy (cancel) một AsyncTask đang chạy trong Android. AsyncTask cho phép thực hiện tác vụ nền và cập nhật UI, nhưng cần cơ chế dừng đúng cách khi không còn cần thiết (ví dụ: người dùng thoát màn hình, nhấn nút Hủy).
Lưu ý quan trọng: AsyncTask đã bị deprecated từ API 30 (Android 11). Google khuyến nghị dùng Coroutines (Kotlin), ExecutorService, RxJava, hoặc WorkManager cho tác vụ nền. Bài viết này chỉ mang tính tham khảo cho dự án cũ.
Các bước thực hiện
Bước 1: Tạo dự án mới
Mở Android Studio, chọn File → New Project và điền thông tin cần thiết.
Bước 2: Layout (res/layout/activity_main.xml)
<?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="Chạy 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="Hủy" />
<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>
Bước 3: Code MainActivity (src/MainActivity.java)
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(v -> {
textView.setText("");
myTask = new DownloadTask().execute("Task1", "Task2", "Task3", "Task4", "Task5");
});
btnCancel.setOnClickListener(v -> {
if (myTask != null) {
myTask.cancel(true); // true = interrupt thread nếu đang sleep/wait
}
});
}
private class DownloadTask extends AsyncTask<String, Integer, List<String>> {
@Override
protected void onPreExecute() {
super.onPreExecute();
textView.setTextColor(Color.BLUE);
textView.setText(textView.getText() + "\n Bắt đầu tác vụ....");
}
@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); // Giả lập tác vụ tốn thời gian
} catch (InterruptedException e) {
e.printStackTrace();
}
// Cập nhật tiến độ (gọi onProgressUpdate)
publishProgress((int) (((i + 1) / (float) count) * 100));
// KIỂM TRA CANCEL - QUAN TRỌNG
if (isCancelled()) {
break; // Thoát vòng lặp sớm
}
}
return taskList;
}
@Override
protected void onCancelled() {
super.onCancelled();
textView.setTextColor(Color.RED);
textView.setText(textView.getText() + "\n Tác vụ đã bị hủy..");
}
@Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
textView.setText(textView.getText() + "\n Hoàn thành: " + progress[0] + "%");
}
@Override
protected void onPostExecute(List<String> result) {
super.onPostExecute(result);
// Chỉ chạy nếu KHÔNG bị cancel
if (!isCancelled()) {
textView.setText(textView.getText() + "\n\n Hoàn tất....");
for (int i = 0; i < result.size(); i++) {
textView.setText(textView.getText() + "\n" + result.get(i));
}
}
}
}
}
Bước 4: Cấu hình 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>
Chạy ứng dụng
Kết nối thiết bị, nhấn Run. Nhấn "Chạy AsyncTask" để bắt đầu, nhấn "Hủy" để dừng giữa chừng.

Các điểm then chốt để hủy AsyncTask đúng cách
- Gọi
cancel(true): Tham sốtruenghĩa làinterrupt()sẽ được gọi trên thread nền (hữu ích nếu thread đangsleep(),wait(), I/O blocking) - Kiểm tra
isCancelled()trongdoInBackground(): Phải kiểm tra định kỳ và thoát sớm (break/return) - Override
onCancelled(): Xử lý UI khi bị hủy (đổi màu, thông báo) - Kiểm tra
isCancelled()trongonPostExecute(): Tránh cập nhật UI không cần thiết sau khi đã hủy
Thay thế hiện đại (Khuyến nghị)
Kotlin Coroutines (Structured Concurrency)
// Trong ViewModel hoặc Activity với lifecycleScope
val job = lifecycleScope.launch {
try {
for (i in 1..5) {
delay(1000) // Không block thread
_progress.value = i * 20
// Tự động hủy khi scope bị hủy (ví dụ: onDestroy)
}
_result.value = "Hoàn tất"
} catch (e: CancellationException) {
_status.value = "Đã hủy"
throw e // Quan trọng: ném lại để coroutine kết thúc đúng
}
}
// Hủy: job.cancel()
ExecutorService + Future
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit(() -> {
for (int i = 0; i < 5; i++) {
if (Thread.currentThread().isInterrupted()) return; // Kiểm tra interrupt
Thread.sleep(1000);
runOnUiThread(() -> updateProgress(i * 20));
}
});
// Hủy:
future.cancel(true); // interrupt = true
executor.shutdown();
WorkManager (cho tác vụ bền vững, chạy ngầm)
// Hủy work theo ID hoặc tag
WorkManager.getInstance(context).cancelWorkById(workId);
// Hoặc
WorkManager.getInstance(context).cancelAllWorkByTag("download_tag");