一、HandlerThread的介紹及使用舉例
HandlerThread是什么鬼?其本質就是一個線程,但是HandlerThread在啟動的時候會幫我們準備好一個Looper,并供外界使用,說白了就是使我們在子線程中更方便的使用Handler,比如沒有HandlerThread我們要在子線程使用Handler,寫法如下:
private Handler mHandler; @Override public void run() { super.run(); Looper.prepare(); mHandler = new Handler(){ @Override public void handleMessage(Message msg) { } }; Looper.loop();}有了HandlerThread就不用我們自己管理Looper了,至于為什么分析源碼的時候就明白了。
HandlerThread使用簡單介紹:
首先我們要初始化HandlerThread然后調用其start方法,也就是開啟線程:
mHandlerThread = new HandlerThread("mHandlerThread");//這里的mHandlerThread其實就是線程的名字mHandlerThread.start();接下來初始化一個Handler并且將mHandlerThread中的Looper作為構造函數參數傳遞給Handler:
mHandler = new Handler(mHandlerThread.getLooper())
這樣就保證了Hnadler運行在子線程。并且需要在適合的時機調用HandlerThread的quit方法或quitSafely方法,如Activity銷毀的時候:
@Overrideprotected void onDestroy() { // super.onDestroy(); //釋放資源 mHandlerThread.quit();}quit()與quitSafely()方法比較(這里只說一些結論,源碼可以自己查看):
相同點:
調用之后MessageQueue消息隊列均不在接受新的消息加入隊列。
不同點:
quit方法把MessageQueue消息池中所有的消息全部清空。quitSafely方法只會清空MessageQueue消息池中所有的延遲消息(延遲消息是指通過sendMessageDelayed或postDelayed等方法發送的消息),非延遲消息則不清除繼續派發出去讓Handler去處理。
接下來我們完整看一下HandlerThread例子源碼:
public class MainActivity extends Activity { private HandlerThread mHandlerThread; private Handler mHandler; private boolean flag; // @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mHandlerThread = new HandlerThread("mHandlerThread"); mHandlerThread.start(); mHandler = new Handler(mHandlerThread.getLooper()) { @Override public void handleMessage(Message msg) { // try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } if(flag){ Log.i("HandlerThread", "更新:"+new Random().nextInt(1000)); } mHandler.sendEmptyMessage(1); } }; } @Override protected void onResume() { // super.onResume(); flag = true; mHandler.sendEmptyMessage(1); } @Override protected void onPause() { // super.onPause(); flag = false; } @Override protected void onDestroy() { // super.onDestroy(); //釋放資源 mHandlerThread.quit(); }}運行程序就會在控制臺看到每隔兩秒有Log打出。至于HandlerThrea的使用就到此為止了,看懂上面小例子就差不多了。
二、HandlerThread的源碼分析
HandlerThread源碼非常簡短,出去注釋不到100行,這里就直接全部貼出來了:
public class HandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; 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; } /** * Call back method that can be explicitly overridden if needed to execute some * setup before Looper loops. */ protected void onLooperPrepared() { } @Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; } /** * 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; } 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; } /** * Returns the identifier of this thread. See Process.myTid(). */ public int getThreadId() { return mTid; } }看第一行就知道了其本質就是一個線程。
6-9行以及17-20行構造函數,也很簡單,就是初始化的時候我們可以定義線程名字,還可以傳入線程優先級。
初始化完成,緊接著調用start()開發線程就會執行run方法邏輯。
30-41行代碼,最重要的就是調用Looper.prepare()以及Looper.loop()方法為我們在子線程準備好一個Looper。并且用變量mLooper記錄,調用getLooper()方法的時候返回。
但是,細心的你肯定發現run()方法中有個notifyAll(),getLooper()中有個wait()為什么要加這些鳥玩意?
大家發現沒在HandlerThread 例子中Handler的創建是在主線程完成的,創建的時候需要調用HandlerThread的getLooper()獲取mLooper作為參數傳遞給Handler的構造函數,而Looper的創建是在子線程中創建的,這里就有線程同步問題了,比如我們調用getLooper()的時候HandlerThread中run()方法還沒執行完,mLooper變量還未賦值,此時就執行了wait()等待邏輯,一直等到run()方法中mLooper被賦值,之后立即執行notifyAll(),然后getLooper()就可以正確返回mLooper了。
明白了吧,不明的話這里需要花些時間好好理解下,好了源碼主要部分就分析完了,看到這里相信你對HandlerThread有了一定的了解了。
HandlerThread 還是比較簡單理解的,好了,本篇到此為止,希望對你有幫助。
新聞熱點
疑難解答