+1

Android - Truyền dữ liệu giữa các threads

Khi bạn làm việc với Android, sẽ có nhiều trường hợp mà bạn muốn tạo một thread từ Activity hoặc Service để thực thi một công việc dài hơi như load dữ liệu từ mạng chẳng hạn. Trong các tình huống đó, thỉnh thoảng bạn cần phải chuyển data đã xử lý dưới thread đến main thread (UI thread) hoặc ngược lại.

Khi làm việc với thread bạn có thể gặp hàng tá các class, các định nghĩa mới như Handler, Looper, HandlerThread … Tôi sẽ cố gắng giải thích một cách đơn giản.

Khi một ứng dụng chạy, nó sẽ được thực thi trong Main thread hay còn gọi là UI thread. Bấy kỳ thread nào khác có thể được tạo ra bằng cách sử dụng lớp java.lang.Thread. Và trong một số trường hợp bạn muốn truyền data tới thread đã tạo hoặc ngược lại.

Chúng ta cùng xem xét một tác vụ mà cần truyền data tới thread, đầu tiên chúng ta tạo mới một worker thread.

STEP 1: Create a worker thread

class MyThread extends Thread {
    @Override
    public void run(){
    }
}

Tại main thread

MyThread mThread = new MyThread();
mThread.start();

Khi mà bạn truyền messages tới một thread hoặc nhận messages từ một thread thì thread nhận cần có một MessageQueue. Mặc định thì một thread tạo từ java.lang.Thread sẽ không có MessageQueue gắn với nó. Nó đơn giản chỉ là một Thread thuần túy giống như hình dưới. Bây giờ chúng ta phải gắn một MessageQueue vào thread của chúng ta. Và để làm điều đó, class Looper cung cấp method prepare() để tạo ra một message queue cho một thread. Chúng ta phải gọi nó từ method run() của thread muốn nhận dữ liệu.

STEP 2: Call the Looper methods

class MyThread extends Thread {
    @Override
    public void run(){
           Looper.prepare();
           Looper.loop();
    }
}

Như bạn thấy, có những 2 method được gọi từ Looper. Method loop() sẽ bắt đầu chạy một vòng lặp xử lý message cho thread hiện tại. Nói một cách đơn giản, nó sẽ bắt đầu tìm kiếm trong message queue và xử lý các messages. Như hình dưới.

Nhưng từ từ đã, ai gửi messages tới MessageQueue và nó được thực hiện như thế nào? Đó chính là Handler. Handler cho phép chúng ta gửi và xử lý Messages (cũng như Runnable objects) được gắn với MessageQueue của thread. Vậy chúng ta cần tạo một Handler. Một điều rất quan trọng cần lưu ý đó là Handler được gắn với thread mà tạo ra nó. Handler cung cấp các method để handle (nhận) các message cũng như gửi và đưa messages vào hàng đợi.

STEP 3: Create a Handler to receive the Messages

class MyThread extends Thread {
    public Handler mHandler;

    @Override
    public void run(){
           Looper.prepare();

           mHandler = new Handler() {
                   public void handleMessage(Message msg) {
                       // Act on the message
                   }
           };
           Looper.loop();
    }
}

Bây giờ, bất cứ một thread nào khác có reference đến mHandler sẽ có khả năng gọi các methods gửi hoặc post của Handler để gửi một message (hoặc một runnable object) tới thread của chúng ta. Đoạn code gửi message sẽ như sau

Message msg = Message.obtain(); msg.obj =  // Some Arbitrary object mHandler.sendMessage(msg);

Tóm tắt lại các bước:

  1. Tạo một Handler bên trong thread muốn nhận dữ liệu, mặc định Handler sẽ được gắn với queue default (Looper)
  2. Nếu thread nhận được tạo sử dụng java.lang.Thread thì chúng ta cần gọi Looper.prepare và Looper.loop() để set up message queue cho thread đó.
  3. Tại thread muốn gửi, hãy chuẩn bị message objects hoặc một runnable object.
  4. Lấy reference tới Handler trong thread nhận và gọi method send/post của nó để gửi một message hoặc runnable object.

HandlerThread Do class java.lang.Thread không chứa một message queue (Looper) nên Android cung cấp một class được gọi là HandlerThread đã có sẵn một message queue. Điểm khác biệt duy nhất đó là khi sử dụng HandlerThread bạn không cần gọi các method của Looper. Khi bạn tạo một HandlerThread, Android sẽ tạo một thread có chứa looper:

HandlerThread myThread = new HandlerThread("Worker Thread");  
myThread.start(); 

Chúng ta có thể phân tách class Handler như sau:

class MyHandler extends Handler { 
    public MyHandler(Looper myLooper) { 
        super(myLooper);
    }
    public void handleMessage(Message msg) { 
    }
} 

Bây giờ trong main thread, chúng ta get looper cho HandlerThread và truyền nó vào khi tạo Handler như sau:

Looper mLooper = myThread.getLooper();  MyHandler mHandler = new MyHandler(mLooper);

Bất kỳ khi nào chúng ta muốn gửi một message từ main thread, chúng ta thực hiện như sau Message msg = mHandler.obtainMessage();

msg.obj =  // Some Arbitrary object
mHandler.sendMessage(msg); 

HẾT Nguồn


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí