安卓學習筆記之HandlerThread

一 、HandlerThread簡介

從字面意思上看,它既與Handler有關係又與Thread有聯繫。確實如此,它繼承自Thread,是一個線程類,同時又內嵌Looper對象。因此,用它開啓的線程的內部可以直接創建一個Handler,並可以與主線程交互。

關於Looper和Handler的協作請參考安卓學習筆記之android消息機制

二、源碼分析

1、構造方法,用於設置線程名和初始化線程優先級。務必要通過start方法來開啓線程

  public HandlerThread(String name) {
    super(name);
    mPriority = Process.THREAD_PRIORITY_DEFAULT;
}

/**
 * Constructs a HandlerThread.
 * @param name
 * @param priority The priority to run the thread at. The value supplied must be from 
 */
public HandlerThread(String name, int priority) {
    super(name);
    mPriority = priority;
}

2、run方法,初始化Looper對象

可以看到HandlerThread內置了Looper消息循環。onLooperPrepared方法在Looper開始loop之前,做一些初始化或設置。普通Thread的run方法一般都做一些耗時操作,但在此run方法做的是創建Lopper並開啓消息輪循,我們可以在線程的外部通過handler發消息讓它做一些事情。注意,不要試圖重寫其run方法並做耗時操作!

@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

/**
 * Call back method that can be explicitly overridden if needed to execute some
 * setup before Looper loops.
 */
protected void onLooperPrepared() {
}

3、獲取Looper對象,用於關聯一個Handler。當線程啓動但Looper沒有創建完成時需等待。

/**
 * This method returns the Looper associated with this thread. If this thread not been started
 * or for any reason is isAlive() returns false, this method will return null. If this thread 
 * has been started, this method will block until the looper has been initialized.  
 * @return The looper.
 */
public Looper getLooper() {
    if (!isAlive()) {
        return null;
    }

    // If the thread has been started, wait until the looper has been created.
    synchronized (this) {
        while (isAlive() && mLooper == null) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
    }
    return mLooper;
}

4、 資源回收

由於run方法不會自動停止(Looper.loop()的原因),所以當我們不使用HandlerThread時,可以調用它的quit或quitSafely方法退出線程,否則線程資源得不到回收。

// 直接退出,不處理餘留消息
 /**
 * Quits the handler thread's looper.
 * <p>
 * Causes the handler thread's looper to terminate without processing any
 * more messages in the message queue.
 */
    public boolean quit() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quit();
        return true;
    }
    return false;
}

//安全退出,等到所有在消息隊列的消息被處理完成。
/**
 * Quits the handler thread's looper safely.
 * <p>
 * Causes the handler thread's looper to terminate as soon as all remaining messages
 * in the message queue that are already due to be delivered have been handled.
 */
public boolean quitSafely() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quitSafely();
        return true;
    }
    return false;
}

三、簡單案例

模擬一個下載任務,在HandlerThread線程中執行耗時操作,並向主線程發送消息以更新UI,當任務完成時,主線程會向子線程發送消息以停止子線程的消息輪循。

    package com.yu.threadspool;

    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.HandlerThread;
    import android.os.Message;
    import android.os.SystemClock;
    import android.util.Log;
    import android.widget.TextView;

    public class HandlerThreadTest extends Activity {
    public static final int MSG_FROM_MAIN = 0;  
    public static final int MSG_FROM_THREAD = 1;
    public static final int MSG_TASK_DONE = 2;
    public static final int MSG_QUIT = 3;
    HandlerThread handlerThread;
    Handler threadHandler; //子線程
    int count = 0;

    TextView tv; // 顯示進度

    Handler mainHanlder = new Handler() {  // 主線程handler

        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MSG_FROM_THREAD:
                tv.setText((String) msg.obj);
                break;

            case MSG_TASK_DONE:
                tv.setText("完成!");
                threadHandler.obtainMessage(MSG_QUIT).sendToTarget();
                break;
            }
        };
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.handler_thread);
        tv = (TextView) findViewById(R.id.tv_text);

        initHandlerThread();

        // 做一些事情,在子線程
        threadHandler.post(new Runnable() {
            public void run() {
                Log.e("TAG", "thread:" + Thread.currentThread().getName());
                while (count < 100) {
                    ++count;
                    Log.e("TAG", "count:" + count);
                    SystemClock.sleep(200); // 模擬耗時
                    Message msg = mainHanlder.obtainMessage(MSG_FROM_THREAD,
                            String.valueOf(count));
                    msg.sendToTarget(); // 向主線程發送消息,更新UI
                }
                // 發送任務完成消息
                mainHanlder.obtainMessage(MSG_TASK_DONE).sendToTarget();

            };
        });
    }

    /**
     * 初始化HandlerThread
     */
    private void initHandlerThread() {
        handlerThread = new HandlerThread("HandlerThread#1");
        handlerThread.start(); // 務必要調用,且必須在關聯Handler之前
        threadHandler = new Handler(handlerThread.getLooper())// 將threadHandler與handlerThread線程關聯
        {
            @SuppressLint("NewApi") @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (msg.what == MSG_QUIT) {

                    handlerThread.getLooper().quitSafely(); // 退出消息輪循,釋放資源
                    Log.e("TAG", Thread.currentThread().getName()+"退出");
                }

            }
        };

    }
}

執行結果

09-08 09:49:45.132: E/TAG(2162): thread:HandlerThread#1
09-08 09:49:45.132: E/TAG(2162): count:1
09-08 09:49:45.332: E/TAG(2162): count:2
09-08 09:49:45.532: E/TAG(2162): count:3
09-08 09:49:45.742: E/TAG(2162): count:4
09-08 09:49:45.942: E/TAG(2162): count:5
        ... ... (省略部分)
09-08 09:50:04.332: E/TAG(2162): count:96
09-08 09:50:04.532: E/TAG(2162): count:97
09-08 09:50:04.742: E/TAG(2162): count:98
09-08 09:50:04.942: E/TAG(2162): count:99
09-08 09:50:05.142: E/TAG(2162): count:100
09-08 09:50:05.342: E/TAG(2162): HandlerThread#1退出
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章