Sử dụng Thread, Asynctask, Handler trong android

I. Thread

Khái niệm

Thread là một tiến trình đơn vị xử lý của máy tính có thể thực hiện một công việc riêng biệt.
Multi-thread là khái niệm cho nhiều tiến trình chạy đồng thời. Một ứng dụng Java ngoài luồng chính có thể có các luồng khác thực thi đồng thời làm ứng dụng chạy nhanh và hiệu quả hơn.

Ưu điểm của đa luồng

Mỗi luồng có thể dùng chung và chia sẻ nguồn tài nguyên trong quá trình chạy, nhưng có thể thực hiện một cách độc lập.
Ứng dụng trách nhiệm có thể được tách + Luồng chính chạy giao diện người dung + Các luồng phụ nhiệm gửi đến luồng chính.

Nhược điểm của đa luồng:

Càng nhiều luồng thì xử lý càng phức tạp
Cần phát hiện tránh các luồng chết, luồng chạy mà không làm gì trong ứng dụng cả

new Thread(new Runnable() {
        public void run() {
            final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
            mImageView.post(new Runnable() {
                public void run() {
                    mImageView.setImageBitmap(bitmap);
                }
            });
        }
    }).start();

II. AsyncTask

Khái niệm

Một chương trình chạy trên Android có thể sẽ có cấu trúc phức tạp. Yêu cầu kết nối đến Server, CSDL, tải file … Nếu chúng ta xử lý các công việc đó trên Main Thread sẽ làm ứng dụng có vẻ chạy chậm hay treo vì chúng làm gián đoạn việc cập nhật, xử lý trên GUI. Có nhiều cách để giải quyết vấn đề này: sử dụng Service, Thread hay đơn giản hơn là dùng Async Task (Asynchronous Task).

Cấu trúc

AsyncTask<params, progress,=”” result=””> có 3 đối số là các Generic Type:
Params: Là giá trị ((biến) được truyền vào khi gọi thực thi tiến trình và nó sẽ được truyền vào doInBackground
Progress: Là giá trị (biến) dùng để update giao diện diện lúc tiến trình thực thi, biến này sẽ được truyền vào hàm onProgressUpdate.
Result: Là biến dùng để lưu trữ kết quả trả về sau khi tiến trình thực hiện xong.
Những đối số nào không sử dụng trong quá trình thực thi tiến trình thì ta thay bằng Void.</params,>

Thông thường trong 1 AsyncTask sẽ chứa 4 hàm

onPreExecute() :Tự động được gọi đầu tiên khi tiến trình được kích hoạt.
doInBackground(): Được thực thi trong quá trình tiến trình chạy nền, thông qua hàm này để ta gọi hàm onProgressUpdate để cập nhật giao diện (gọi lệnh publishProgress). Ta không thể cập nhật giao diện trong hàm doInBackground().
onProgressUpdate (): Dùng để cập nhật giao diện lúc runtime có thể dùng hiện progressdialog ở đây.
onPostExecute(): Sau khi tiến trình kết thúc thì hàm này sẽ tự động sảy ra. Ta có thể lấy được kết quả trả về sau khi thực hiện tiến trình kết thúc ở đây.
Trong 4 hàm trên thì hàm doInBackground() bắt buộc phải tồn tại, còn các hàm khác có thể khuyết, nhưng theo Tui các bạn nên sử dụng đầy đủ 4 hàm đã nêu.
Đối với AsyncTask thì ta cần tạo một lớp kế thừa từ AsyncTask, sau đó từ MainActivity ta gọi hàm execute() của tiến trình này là OK.

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }

Thực thi AsyncTask:

 new DownloadFilesTask().execute(url1, url2, url3);

III. Handler

  • Khi một tiến trình được tạo cho một ứng dụng, main thread của nó được dành riêng để chạy một message queue, queue này quản lý các đối tượng bậc cao của ứng dụng (activity, intent receiver, v.v..) và các cửa sổ mà chúng tạo ra.
  • Ta có thể tạo các thead phụ, chúng tương tác với thread chính của ứng dụng qua một Handler.
  • Khi ta tạo một Handler mới, nó được gắn với message queue của thread tạo ra nó – từ đó trở đi, nó sẽ gửi các message và các runnable tới message queue đó và thực thi chúng khi chúng ra khỏi message queue.
  • Hai ứng dụng chính của Handler:
    • xếp lịch cho các message và runnable cần được thực thi vào thời điểm nào đó trong tương tai, và
    • xếp hàng một action cần thực hiện tại một thread khác.
handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);   
                //Nhận message từ thread
                 String message = msg.obj.toString();
            }
        };

//Tạo tiến trình con
Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                    Message msg = handler.obtainMessage();
                    // gán dữ liệu cho msg Mainthread, lưu vào biến obj
                    //chú ý ta có thể lưu bất kỳ kiểu dữ liệu nào vào obj
                    msg.obj = "www.androidcobancom";
                    //gửi trả lại message cho Mainthread
                    handler.sendMessage(msg);
                }
            }
        });
        //start thread
        thread.start();

Xem thêm các bài viết khác:

Android background processing handler, asyncTask part 1

Sử dụng asynctask multiple parameter

Nguyễn Linh

Chia sẻ để cùng tiến bộ...