【安卓筆記】HandlerThread源碼剖析,安卓handlerthread
有時候我們需要在應用程式中建立一些常駐的子線程不定期地執行一些計算型任務,這時候可以考慮使用HandlerThread,它具有建立帶訊息迴圈的子線程的作用。
一、HanderThread使用樣本先熟悉下HandlerThread的一般用法。我們建立一個如下所示的Activity:
package com.example.handlethreaddemo;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;public class MainActivity extends Activity{private Looper mLooper;private MyHandler mHandler;private static final String TAG = "MainActivity";private static class MyHandler extends Handler{public MyHandler(Looper looper){super(looper);}@Overridepublic void handleMessage(Message msg){switch (msg.what){case 1:Log.i(TAG, "當前線程是"+Thread.currentThread().getName()+",TEST 1");break;case 2:Log.i(TAG, "TEST 2");break;}}}@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//建立HandlerThread對象HandlerThread myHandleThread = new HandlerThread("HandlerThread<子線程>");//啟動HandlerThread---->內部將啟動訊息迴圈myHandleThread.start();//擷取LoopermLooper = myHandleThread.getLooper();//構造Handler,傳入子線程中的LoopermHandler = new MyHandler(mLooper);/* * 註:經過上述步驟,Handler將綁定子線程的Looper和MessageQueue. * 也就是說handleMessage最終由子線程調用 * */mHandler.sendEmptyMessage(1);Log.i(TAG,"當前線程是:"+Thread.currentThread().getName());}}
使用HandlerThread內部提供的Looper物件建構Handler對象,然後在ui線程中向Handler發送訊息。log日誌如下:
可見發送訊息的線程為UI線程,而處理訊息的線程為子線程,也就是說,我們在
子線程中建立了訊息迴圈。一般情況下,我們總是在UI線程中建立Handler對象,並使用介面組件提供的預設Looper,這個Looper綁定在UI線程上。所以我們線上程中向Handler發送訊息時,最終的處理是在主線程中進行的。但正如開篇所說,我們有時需要構建常駐的子線程以不定期執行計算型任務,這時在子線程中建立訊息迴圈將非常有用。
二、HandlerThread源碼剖析HandlerThread源碼十分精簡。HandlerThread繼承自java.lang.Thread,並封裝了Looper對象:
int mPriority;//優先順序 int mTid = -1;//線程標誌 Looper mLooper;//訊息迴圈
可通過構造器注入線程優先順序,預設優先順序為Process.THREAD_PRIORITY_DEFAULT
public HandlerThread(String name, int priority) { super(name); mPriority = priority; }
核心邏輯為run方法(複寫Thread類的run方法):
public void run() { mTid = Process.myTid(); Looper.prepare();//建立Looper對象 synchronized (this) { mLooper = Looper.myLooper();//擷取與本線程綁定的Looper notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared();//回調介面,預設為空白實現。 Looper.loop();//啟動訊息迴圈--->may be blocked mTid = -1; }
外界可通過getLooper方法擷取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();//非同步等待Looper準備好 } catch (InterruptedException e) { } } } return mLooper; }
如果調用getLooper方法時,Looper未準備好,那麼將會阻塞線程,直到準備好Looper對象。外界可調用quit方法終止訊息迴圈:
public boolean quit() { Looper looper = getLooper(); if (looper != null) { looper.quit();//內部調用looper類的quit return true; } return false; }
附:Looper類相信大家都不陌生,這裡順便簡單提下(之前寫過Handler和Looper):Looper.prepare方法將會建立一個Looper對象(Looper類的構造器為私人,不可new),並將其放到ThreadLocal中,意為線程局部變數:
public static void prepare() { prepare(true); } private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
然後通過Looper.myLooper方法返回與本線程綁定的Looper,正是剛建立的Looper:
public static Looper myLooper() { return sThreadLocal.get(); }
Looper.loop方法將啟動訊息迴圈,不斷從其內部封裝的訊息佇列MessageQueue中取出訊息,交由Handler執行。
public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } msg.target.dispatchMessage(msg); if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycle(); } }
沒有訊息時,訊息佇列會阻塞。
以上就是HandlerThread的全部內容。
我在電視看到了(美國安卓筆記本平板電腦)的廣告說原價3500元,如果在他們全部隨機播放廣告時打進訂購緊
可以呢很好呀,但是要注意,別給他們錢就行事先說好,想辦法把錄下了取證,記住千萬別出一角錢。 都說不要出一分錢了。