Looper, Handler and HandlerThread in android
Bài đăng này đã không được cập nhật trong 4 năm
MultiThreading và Task running là những khái niệm quen thuộc trong lập trình. Trong Java java.util.concurrent là package chứa các utility class giúp ích trong việc lập trình song song (concurrent programming) và Fork/Join framework là một framework hiện thực của ExecutorService interface giúp tận dụng tối đa khả năng của bộ đa xử lý multiple processors. Trong Android, Looper, Handler và HandlerThread là cách giải quyết các vấn đề liên quan tới lập trình bất đồng bộ.
Đặt vấn đề
Trong java, Thread thông thường mang ý nghĩa chỉ sử dụng một lần nghĩa là  khởi tạo và chết đi sau khi thực thi hàm run().
Bản thân Thread là con dao 2 lưỡi, chúng ta có thể tăng tốc việc thực thi bằng cách phân phối task giữa các Thread, tuy nhiên, ngược lại có thể làm chậm việc thực thi các task khi mà số lượng Thread vượt quá số lượng có thể.
Vì vậy cách tốt nhất là phải có 1 số lượng tối ưu Thread và tái sử dụng chúng cho việc thực thi task. (Tham khảo thêm Sử dụng ThreadPoolExecutor trong android). Trong bài viết này, chúng ta sẽ cùng nhau tái sử dụng Thread với Looper và Handler.
Tái sử dụng Thread
- Giữ Thread hoạt động bởi 1 vòng lặp trong hàm run()của nó dùngLooper
- Các task được thực thi nối tiếp nhau bởi Thread và được duy trì trong một hàng đợi (MessageQueue)
- Hủy Threadsau khi hoàn thành.
Looper, Handler, HandlerThread

Hệ thống Android trãi qua các bước:
- MessageQueuelà hàng đợi chứa nhiệm vụ cần được thực thi.
- Handlerthực hiện enqueues task từ- MessageQueuedùng- Loopervà đồng thời thực thi chúng khi nhận từ- MessageQueue.
- Looperlà 1- workergiữ cho- Threadtồn tại, nó sẽ vòng qua- MessageQueuevà gởi các- messagetới các- Handlertương ứng để thực thi.
- Cuối cùng Threadbị hủy từ lời gọi hàmquit()củaLooper.
Mỗi Thread chỉ có thể có một
Looperduy nhất và có thế có nhiềuHandlerliên kết với nó.
Tạo Looper và MessageQueue cho Thread
Cách tự tạo và tự quản lý:
Với cách này, bạn sẽ tự tạo 1 Thread với Looper và quản lý chúng. Mặc định, Handler sẽ liên kết ngầm (implicitly) với Thread mà nó đc khởi tạo qua Looper, tuy nhiên bạn có thể buộc nó vào 1 Thread khác bằng cách cung cấp rõ trong constructor lúc khởi tạo.
class LooperThread extends Thread {
      public Handler handler; 
 
      public void run() { 
         // Creating Looper and MessageQueue for this Thread
          Looper.prepare();
 
          handler = new Handler() { 
              public void handleMessage(Message msg) { 
                 // process incoming messages here
                 // this will run in non-ui/background thread
              } 
          }; 
         // Associate the Thread with its Looper and MessageQueue
          Looper.loop();
      } 
  }
- Thread nhận 1 LoopervàMessageQueuebằng cách gọiLooper.prepare()ngay khi bắt đầu thực thi (run()).
- Looper.prepare()sẽ xác định Thread đang gọi, tạo 1 đối tượng- Loopervà- MessageQueuevà kết nối chúng với Thread bên trong- ThreadLocal.
- Looper.loop()cần được gọi để bắt đầu kết nối.
Trong ví dụ trên, hãy cùng xem xét cách tạo Handler cho Thread và cách mà Handler nhận, gởi message:
handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        // process incoming messages here
        // this will run in the thread, which instantiates it
    }
};
Handler gởi message tới MessageQueue bởi Handler có thể thông qua 2 cách:
- Message: là class chứa các phương thức hữu ích khác nhau để gởi dữ liệu.
Message msg = Message.obtain();
msg.obj = "Send message From Me";
handler.sendMessage(msg);
new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        // this will run in the main thread
    }
});
Ở ví dụ này, chúng ta tạo một Handler và cung cấp Looper liên kết với Main Thread. Khi post Runnable, nó sẽ được thêm vào MessageQueue của Main Thread và sau đó được thực thi trong Main Thread.
Tự tạo một Thread và cung cấp Looper, MessageQueue đôi khi gây khó khăn cho lập trình viên. Vì vậy, Android cung cấp cho chúng ta HandlerThread (kế thừa từ Thread) để đơn giản hóa việc thực thi task. Bên trong nó là những thứ tương tự mà chúng ta đã làm ở trên nhưng đã được tối ưu. Do vậy, hãy nên sử dụng HandlerThread.
Cách tạo dùng HandlerThread
private class MyHandlerThread extends HandlerThread {
    Handler handler;
    public MyHandlerThread(String name) {
        super(name);
    }
    @Override
    protected void onLooperPrepared() {
        // Only instantiates the Handler when looper is prepared
        // So, Handler can be associated with that Looper
        handler = new Handler(getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                // process incoming messages here
                // this will run in non-ui/background thread
            }
        };
    }
}
Note:
- Looperchỉ- preparedsau khi hàm- start()của- HandlerThreadđược thực thi.
- Một Handlercó thể được liên kết với mộtHandlerThreadchỉ khiLoopercủa nó đượcprepared.
- HandlerThreadcần gọi hàm- quit()để giải phóng resource và dừng quá trình thực thi.
Một cách khác để khởi tạo HandlerThread
HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
Tham khảo
https://blog.mindorks.com/android-core-looper-handler-and-handlerthread-bd54d69fe91a#.kc15r6z0b
https://blog.nikitaog.me/2014/10/11/android-looper-handler-handlerthread-i/
https://blog.nikitaog.me/2014/10/11/android-looper-handler-handlerthread-ii/
All rights reserved
 
  
 