2017年11月7日 星期二

Android系統筆記 - Java HandlerThread

Java 的 Thread 已經被封裝成了幾種易用的形式, 簡單介紹一下幾個重點:

Runnable 
可以理解為"任務內容"
我們會把要完成的一件工作寫在Runnable的物件裡面.
例如這樣:
Runnable task = new Runnable() {
    public void run() {
        Log.e("Start run!");
    }
};

Thread
單執行序, 負責處理一個 Runnable 的物件.
用法也很簡單, 我們可以直接把上面那個 task 直接丟進去:
Thread oneTimeThread = new Thread(task);
oneTimeThread.start();
這樣就會開另外一個執行序去執行一次 task

另外Thread也有一個建構子是沒有帶入Runnable物件的,
這樣子呼叫start()就會直接執行Thread裡面的run()方法,
一般使用在你的物件去繼承了 Thread 的時候, 例如這樣:

public class myThread extends Thread {
    @Override
    public void run() {
        System.out.println("Thread start running!");
        for (;;) {
            System.out.println("Thread keep running!");
        }
    }

    public static void main(String[] argv) {
        Thread t = new myThread();
        t.start();
        for (;;) {
            System.out.println("Main Thread");
        }
    }
}

執行以後就會交錯印出訊息, 可能像這樣:
Main Thread
Main Thread
Thread start running!
Thread keep running!
Thread keep running!
Main Thread
Thread keep running!
Main Thread
(因為執行序的關係, main通常會先開始跑)

你也可以嘗試將 infinite for loop 換成只跑10次來觀察看看.
另外需要一提的是, 這個 Thread 物件也可以直接呼叫 run() method,
這時就會在 main thread 執行, 而不會另外開一個執行序去跑, 所以執行結果會變成這樣:
(把 infinite for loop 換成只跑10次)

Thread start running!
Thread keep running!
Thread keep running!
Main Thread
Main Thread
=> 等到 run() 方法執行完之後才會往下跑


HandlerThread
相較於上面的單執行序, 這個物件幫你封裝了MessageQueue在裏頭,
它的定位很像是 Native layer 的 Thread 物件, 啟動之後會自動運行 threadLoop(),
並且會等待事件進入時才開始工作 (可以想像成它呼叫了 pollOnce(-1))

handlerThread開始執行之後, 會開啟另外一個執行序來等待工作. (*這時候還沒有task放進去跑)
我會把它拿來處理asynchronous訊息的溝通, 用法如下:
HandlerThread workThread = new HandlerThread("WorkThread");
workThread.start(); // 開始等待事件進入

// 分發事件的方式要使用 Handler 物件來進行分配, 關於 Handler 請往下看
Handler workHandler = new Handler(workThread.getLooper());
workHandler.post(task);

// 除了 post 以外, 還有 postAtTime, postDelayed 等形式可以來控制 task 執行到的時間

* 因為這個執行序沒有所謂的執行結束, 所以不用的時候記得要關閉掉它
(例如, 放在 constructor 跟 destructor)

Handler
這個物件除了可以使用post()分配事件給HandlerThread,
還有一個用法是去override handleMessage(), 將事件預先定義好, 並使用 Message 來開始工作.
Handler workHandler = new Handler(workThread.getLooper()) {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {
            case 1:
                Log.e("Handler", "Received message");
                break;
            default:
                Log.e("Handler", "Unsupprted message");
                break;
        }
    }
}

workHandler.sendEmptyMessage(1);
(有興趣進去看 Handler.java的話, 你會發現 post() 函數也是將 Runnable 物件封裝為 Message)

沒有留言:

張貼留言

不定參數印 log

From the UNIXProcess_md.c #ifdef DEBUG_PROCESS   /* Debugging process code is difficult; where to write debug output? */ static void deb...