CyStack logo
  • Sản phẩm & Dịch vụ
  • Giải pháp
  • Bảng giá
  • Công ty
  • Tài liệu
Vi

vi

Trang chủHướng dẫnTìm hiểu về AsyncTask trong Android
Android

Tìm hiểu về AsyncTask trong Android

CyStack blog 6 phút để đọc
CyStack blog25/08/2025
Locker Avatar

Chris Pham

Technical Writer

Locker logo social
Reading Time: 6 minutes

Hôm nay, chúng ta sẽ cùng nhau đi sâu vào một công cụ cực kỳ hữu ích trong Android: AsyncTask. Chúng ta sẽ tìm hiểu nó là gì, tại sao nó lại quan trọng, và cách chúng ta triển khai nó trong một ứng dụng thực tế. Việc hiểu và sử dụng AsyncTask đúng cách giúp ứng dụng của bạn luôn mượt mà, phản hồi nhanh chóng, mang lại trải nghiệm tốt nhất cho người dùng. Chúng ta sẽ phát triển một ứng dụng Android mẫu đơn giản để thấy rõ cách AsyncTask hoạt động trong nền.

asynctask trong android

Android AsyncTask là gì?

Android AsyncTask là một lớp trừu tượng (abstract class) mà Android cung cấp, cho phép chúng ta thực hiện các tác vụ nặng ở chế độ nền (background) và giữ cho luồng giao diện người dùng (UI thread) luôn nhẹ, từ đó giúp ứng dụng phản hồi nhanh hơn.

Khi một ứng dụng Android khởi chạy, nó chạy trên một luồng duy nhất, chúng ta gọi đó là UI thread hoặc Main thread. Với mô hình luồng đơn này, các tác vụ cần nhiều thời gian để hoàn thành, như tải dữ liệu từ internet, xử lý hình ảnh lớn, hoặc truy vấn cơ sở dữ liệu phức tạp, có thể chặn luồng UI, khiến ứng dụng bị treo (non-responsive) và người dùng thấy thông báo ANR.

Để khắc phục vấn đề này, chúng ta sử dụng Android AsyncTask để thực hiện các tác vụ nặng ở chế độ nền trên một luồng riêng biệtvà chuyển kết quả trở lại luồng UI một cách an toàn. Nhờ đó, việc sử dụng AsyncTask trong ứng dụng Android luôn giữ cho luồng UI phản hồi kịp thời.

Các phương thức cơ bản chúng ta sử dụng trong một lớp Android AsyncTask bao gồm:

  • doInBackground(): Chúng ta đặt mã cần thực thi ở chế độ nền vào phương thức này. Trong phương thức này, chúng ta có thể gửi kết quả cập nhật tiến trình nhiều lần về luồng UI bằng phương thức publishProgress(). Để báo hiệu quá trình xử lý nền đã hoàn thành, chúng ta chỉ cần sử dụng câu lệnh return để trả về kết quả cuối cùng.
  • onPreExecute(): Chúng ta thực thi mã trong phương thức này trước khi quá trình xử lý nền bắt đầu. Đây là nơi lý tưởng để hiển thị một ProgressDialog hoặc thiết lập trạng thái UI ban đầu.
  • onPostExecute(): Hệ thống gọi phương thức này sau khi phương thức doInBackground() hoàn thành quá trình xử lý. Kết quả từ doInBackground() được truyền làm tham số vào phương thức này, và chúng ta sử dụng nó để cập nhật UI cuối cùng.
  • onProgressUpdate(): Phương thức này nhận các cập nhật tiến trình từ phương thức doInBackground() (được công bố thông qua publishProgress()). Chúng ta có thể sử dụng các cập nhật tiến trình này để cập nhật luồng UI, ví dụ như cập nhật thanh tiến trình.

Ba kiểu generic chúng ta sử dụng trong một lớp Android AsyncTask là:

  • Params: Kiểu của các tham số chúng ta truyền vào tác vụ khi thực thi.
  • Progress: Kiểu của các đơn vị tiến trình chúng ta công bố trong quá trình tính toán nền.
  • Result: Kiểu của kết quả cuối cùng từ quá trình tính toán nền.

Ví dụ về Android AsyncTask

Để khởi tạo và chạy một AsyncTask, chúng ta cần đoạn mã sau trong lớp MainActivity của mình:

MyTask myTask = new MyTask();
myTask.execute();

Trong đoạn mã trên, chúng ta sử dụng một tên lớp mẫu (MyTask) mở rộng AsyncTask, và phương thức execute() khởi động luồng nền. Lưu ý quan trọng khi sử dụng AsyncTask:

  • Chúng ta phải tạo và gọi instance của AsyncTask trên luồng UI.
  • Chúng ta không bao giờ tự gọi các phương thức được ghi đè trong lớp AsyncTask (onPreExecute(), doInBackground(), onProgressUpdate(), onPostExecute()). Hệ thống tự động gọi chúng theo đúng vòng đời.
  • Chúng ta chỉ có thể gọi một AsyncTask duy nhất một lần. Gọi lại nó sẽ gây ra ngoại lệ (exception).

Trong bài hướng dẫn này, chúng ta sẽ triển khai một AsyncTask thực hiện một quá trình “ngủ” (giả lập một tác vụ tốn thời gian) trong khoảng thời gian do người dùng thiết lập.

Cấu trúc dự án Android Async Task

Android AsyncTask

Mã nguồn ví dụ Android AsyncTask

Đầu tiên, bố cục XML được định nghĩa trong tệp activity_main.xml như sau. Chúng ta thiết kế một giao diện đơn giản với một EditText để người dùng nhập thời gian “ngủ”, một Button để kích hoạt AsyncTask, và một TextView để hiển thị kết quả và tiến trình.

activity_main.xml

<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" >

    <TextView
        android:id="@+id/tv_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="10pt"
        android:textColor="#444444"
        android:layout_alignParentLeft="true"
        android:layout_marginRight="9dip"
        android:layout_marginTop="20dip"
        android:layout_marginLeft="10dip"
        android:text="Sleep time in Seconds:"/>
    <EditText
        android:id="@+id/in_time"
        android:layout_width="150dip"
        android:layout_height="wrap_content"
        android:background="@android:drawable/editbox_background"
        android:layout_toRightOf="@id/tv_time"
        android:layout_alignTop="@id/tv_time"
        android:inputType="number"
        />
    <Button
        android:id="@+id/btn_run"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Run Async task"
        android:layout_below="@+id/in_time"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="64dp" />
    <TextView
        android:id="@+id/tv_result"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="7pt"
        android:layout_below="@+id/btn_run"
        android:layout_centerHorizontal="true" />
</RelativeLayout>

Trong bố cục trên, chúng ta sử dụng một drawable có sẵn của Android (@android:drawable/editbox_background) làm đường viền cho EditText.

Tiếp theo là lớp MainActivity.java, nơi chúng ta triển khai logic chính và định nghĩa AsyncTask lồng bên trong:

package com.journaldev.asynctask;

import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity; // Sử dụng androidx cho các dự án hiện đại
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private Button button;
    private EditText time;
    private TextView finalResult;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Khởi tạo các View từ layout
        time = findViewById(R.id.in_time); // Sử dụng findViewById thay vì ép kiểu cho các phiên bản Android mới hơn
        button = findViewById(R.id.btn_run);
        finalResult = findViewById(R.id.tv_result);

        // Đặt lắng nghe sự kiện click cho nút
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // Khởi tạo một instance mới của AsyncTaskRunner
                AsyncTaskRunner runner = new AsyncTaskRunner();
                // Lấy thời gian ngủ từ EditText
                String sleepTime = time.getText().toString();
                // Thực thi AsyncTask với thời gian ngủ làm tham số
                runner.execute(sleepTime);
            }
        });
    }

    // Định nghĩa lớp AsyncTask lồng bên trong
    private class AsyncTaskRunner extends AsyncTask<String, String, String> {

        private String resp;
        ProgressDialog progressDialog;

        @Override
        protected String doInBackground(String... params) {
            // Cập nhật tiến trình cho biết tác vụ đang "ngủ"
            publishProgress("Sleeping..."); // Gọi onProgressUpdate()
            try {
                // Chuyển đổi thời gian từ chuỗi sang số nguyên và nhân với 1000 (miliseconds)
                int timeToSleep = Integer.parseInt(params[0]) * 1000;
                // Dừng luồng hiện tại trong khoảng thời gian đã cho, giả lập tác vụ nặng
                Thread.sleep(timeToSleep);
                // Tạo thông báo kết quả
                resp = "Slept for " + params[0] + " seconds";
            } catch (InterruptedException e) {
                // Xử lý nếu luồng bị ngắt
                e.printStackTrace();
                resp = "Error: " + e.getMessage();
            } catch (Exception e) {
                // Xử lý các lỗi khác
                e.printStackTrace();
                resp = "Error: " + e.getMessage();
            }
            // Trả về kết quả cuối cùng cho onPostExecute
            return resp;
        }

        @Override
        protected void onPostExecute(String result) {
            // Sau khi tác vụ nền hoàn thành, loại bỏ ProgressDialog
            if (progressDialog != null && progressDialog.isShowing()) {
                progressDialog.dismiss();
            }
            // Cập nhật kết quả cuối cùng lên TextView trên luồng UI
            finalResult.setText(result);
        }

        @Override
        protected void onPreExecute() {
            // Trước khi tác vụ nền bắt đầu, hiển thị ProgressDialog
            progressDialog = ProgressDialog.show(MainActivity.this,
                    "ProgressDialog",
                    "Wait for " + time.getText().toString() + " seconds");
        }

        @Override
        protected void onProgressUpdate(String... text) {
            // Cập nhật TextView với thông tin tiến trình nhận được từ doInBackground
            finalResult.setText(text[0]);
        }
    }
}

Trong đoạn mã trên, chúng ta sử dụng lớp AsyncTaskRunner để thực hiện các thao tác của AsyncTask. Thời gian theo giây được truyền làm tham số cho lớp, và một ProgressDialog sẽ hiển thị trong khoảng thời gian đã cho để người dùng biết ứng dụng đang xử lý. Khi bạn chạy ứng dụng và nhập một số giây (ví dụ: 5 giây), bạn sẽ thấy ProgressDialog xuất hiện, sau đó là thông báo kết quả trên TextView.

Android AsyncTask

Kết Luận

Qua bài blog này, chúng ta đã cùng nhau khám phá Android AsyncTask – một công cụ mạnh mẽ giúp chúng ta giải quyết vấn đề ứng dụng bị treo do các tác vụ nặng. Việc nắm vững AsyncTask là một bước đệm vững chắc giúp bạn hiểu sâu hơn về cơ chế đa luồng trong Android và mở ra cánh cửa cho những kiến thức nâng cao hơn.

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất