Android HandlerThread詳解

轉載請註明出處:http://blog.csdn.net/vnanyesheshou/article/details/75073307

對於Handler不太懂的可以參考我的這兩篇文章:
Android Handler的基本使用
深入理解Handler、Looper、Messagequeue
這篇主要說一下HandlerThread的使用方法,及分析下其源碼。


1 HandlerThread

HandlerThread類介紹

Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.

HandlerThread是Android API提供的一個方便、便捷的類,使用它我們可以快速的創建一個帶有Looper的線程。Looper可以用來創建Handler實例。注意:start()仍然必須被調用。

如下是HandlerThread使用的demo。

package com.zpengyong.hand;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
    private final static String TAG = "MainActivity";

    private Button mGet;
    private TextView mResult;

    protected final int MSG_GET = 1;
    protected final int MSG_RESULT = 2;

    private HandlerThread mHandlerThread;
    //子線程中的Handler實例。
    private Handler mSubThreadHandler;
    //與Ui線程綁定的Handler實例。
    private Handler mUiHandler = new Handler(){
        public void handleMessage(Message msg) {
            Log.i(TAG, "mUiHandler handleMessage thread:"+Thread.currentThread());
            switch (msg.what) {
            case MSG_RESULT:
                mResult.setText((String)msg.obj);
                break;
            default:
                break;
            }
        };
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i(TAG, "onCreate thread:"+Thread.currentThread());
        mGet = (Button) findViewById(R.id.get);
        mGet.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mSubThreadHandler.sendEmptyMessage(MSG_GET);
            }
        });
        mResult = (TextView) findViewById(R.id.result);

        initHandlerThraed();
    }

    private void initHandlerThraed() {
        //創建HandlerThread實例
        mHandlerThread = new HandlerThread("handler_thread");
        //開始運行線程
        mHandlerThread.start();
        //獲取HandlerThread線程中的Looper實例
        Looper loop = mHandlerThread.getLooper();
        //創建Handler與該線程綁定。
        mSubThreadHandler = new Handler(loop){
            public void handleMessage(Message msg) {
                Log.i(TAG, "mSubThreadHandler handleMessage thread:"+Thread.currentThread());
                switch(msg.what){
                case MSG_GET:
                    try { //模擬延時處理
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    double number = Math.random();
                    String result = "number:"+number;
                    //向ui線程發送消息,更新ui。
                    Message message = new Message();
                    message.what = MSG_RESULT;
                    message.obj = result;
                    mUiHandler.sendMessage(message);
                    break;
                default:
                    break;
                }
            };
        };
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy");
        //退出HandlerThread的Looper循環。
        mHandlerThread.quit();
    }
}

上述代碼比較簡單,功能也比較簡單,可以在此基礎上進行擴展。
在Actvitiy創建的時候調用initHandlerThraed()函數:

  1. 創建HandlerThread線程
  2. 運行線程
  3. 獲取HandlerThread線程中的Looper實例
  4. 通過Looper實例創建Handler實例,從而使mSubThreadHandler與該線程連接到一起。

多次點擊按鈕,打印信息如下所示:

07-13 05:15:07.662: I/MainActivity(1472): onCreate thread:Thread[main,5,main]
07-13 05:15:45.382: I/MainActivity(1472): mSubThreadHandler handleMessage thread:Thread[handler_thread,5,main]
07-13 05:15:46.402: I/MainActivity(1472): mUiHandler handleMessage thread:Thread[main,5,main]
07-13 05:15:46.412: I/MainActivity(1472): mSubThreadHandler handleMessage thread:Thread[handler_thread,5,main]
07-13 05:15:47.412: I/MainActivity(1472): mUiHandler handleMessage thread:Thread[main,5,main]
.....

點擊按鈕,向mSubThreadHandler發送消息,mSubThreadHandler中接收到消息進行處理,由打印可知mSubThreadHandler的handleMessage方法運行在子線程中。
模擬耗時操作,生成隨機數,然後向主線程中(mUiHandler)發送消息(Message)。

mUiHandler的handleMessage方法運行在主線程,可以用來更新Ui界面。

Activity銷燬的時候,調用mHandlerThread.quit(),退出HandlerThread的Looper循環。

效果圖如下:
這裏寫圖片描述


2 HandlerThread源碼分析

源碼路徑路徑:frameworks/base/core/java/android/os/HandlerThread.java

先看下HandlerThread的構造方法。

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    //@param name 線程名
    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 
     * {@link android.os.Process} and not from java.lang.Thread.
     */
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    。。。。

HandlerThread是Thread(線程)的子類。創建一個HandlerThread實例,也就是創建了一個特殊的線程實例。
HandlerThread提供了兩個構造方法:

  • HandlerThread(String name) 參數爲線程名稱,線程優先級爲Process.THREAD_PRIORITY_DEFAULT。
  • HandlerThread(String name, int priority),name爲線程名稱,priority爲設置的線程優先級。

我們知道線程需要通過start()方法來運行線程,HandlerThread也是這樣的。接着看下線程運行的run()方法。

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

@Override
public void run() {
    //獲取進程id
    mTid = Process.myTid();
    //創建Looper實例
    Looper.prepare();
    synchronized (this) {
        //獲取當前線程的Looper實例
        mLooper = Looper.myLooper();
        notifyAll();
    }
    //設置線程優先級
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    //開始循環
    Looper.loop();
    mTid = -1;
}

由run方法可知HandlerThrea線程運行創建了Looper實例,並開啓了Looper循環,循環從消息隊列中獲取消息並給Handler進行處理。對於Looper不太明白的可以參考這篇深入理解Handler、Looper、Messagequeue

onLooperPrepared()在Looper循環之前調用,如果需要在Looper循環之前執行一些設置,可以顯式覆蓋此方法。

接着看獲取Looper實例

//獲取HandlerThread線程中的Looper實例
Looper loop = mHandlerThread.getLooper();

對應源碼:

//此方法返回與此線程關聯的Looper。 如果此線程未啓動或由於任何原因isAlive()返回false,此方法將返回null。
public Looper getLooper() {
    if (!isAlive()) {
        return null;
    }

    // 如果這個線程已經啓動,將會被阻塞,直到mLooper被初始化爲止。
    synchronized (this) {
        while (isAlive() && mLooper == null) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
    }
    return mLooper;
}

mHandlerThread.getLooper()獲取與該線程綁定的Looper實例。mLooper是在HandlerThread的run()方法中賦值的(也就是在子線程中),getLooper是我們在主線程中調用,該方法會阻塞直到mLooper賦值。

然後demo中通過該looper實例創建Handler

//創建Handler與該線程綁定。
mSubThreadHandler = new Handler(loop)

你可能會好奇爲什麼要這樣長久Handler而不是“new Handler()“這樣呢?因爲我們要創建的Handler要與子線程綁定到一起,要處理子線程中的消息,所以要通過子線程中的looper(有線程對應的消息隊列)實例創建Handler。這樣通過mSubThreadHandler發送的消息會添加到子線程中的消息隊列中,然後Looper實例消息進行分發,交給mSubThreadHandler進行處理。

HandlerThread提供的線程退出方法:

public boolean quit() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quit();
        return true;
    }
    return false;
}
public boolean quitSafely() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quitSafely();
        return true;
    }
    return false;
}

quit和quitSafely都是退出HandlerThread的消息循環。其分別調用Looper的quit和quitSafely方法。
quit方法會將消息隊列中的所有消息移除(延遲消息和非延遲消息)。
quitSafely會將消息隊列所有的延遲消息移除,非延遲消息派發出去讓Handler去處理。quitSafely相比於quit方法安全之處在於清空消息之前會派發所有的非延遲消息

HandlerThread適合處理本地IO讀寫操作(數據庫,文件),因爲本地IO操作大多數的耗時屬於毫秒級別,對於單線程 + 異步隊列的形式 不會產生較大的阻塞。而網絡操作相對比較耗時,容易阻塞後面的請求,因此在這個HandlerThread中不適合加入網絡操作。

至此HandlerThread就說完了。有什麼問題歡迎大家指正、交流。

DEMO下載:http://www.demodashi.com/demo/10628.html

發佈了129 篇原創文章 · 獲贊 270 · 訪問量 97萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章