Handler,MessageQueue,Looper的關係
-
Looper的做用是在線程中處理消息的異步
-
MessageQueue用來存儲消息的隊列ide
-
Handler使用來定義具體處理消息的方式,以及發送消息;Android主線程中持有一個能夠更新UI的Handler;對其餘的線程,若是須要處理消息,能夠本身new一個Handler在線程的 run 方法中。oop
-
ThreadLocal:MessageQueue對象,和Looper對象在每一個線程中都只會有一個對象,怎麼能保證它只有一個對象,就經過ThreadLocal來保存。Thread Local是一個線程內部的數據存儲類,經過它能夠在指定線程中存儲數據,數據存儲之後,只有在指定線程中能夠獲取到存儲到數據,對於其餘線程來講則沒法獲取到數據。源碼分析
一.Looperui
源碼分析: Looper.prepare()方法;建立一個Looper的實例,可是該實例在一個線程中只能有一個;保存在ThreadLocal中,若是發現已經存在了Looper對象,會拋出一個異常。this
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.loop()方法;loop()方法中有一個無限的循環。for(;;)那一段;線程執行到loop()方法以後會一直留在loop()方法中,直到被打斷終止 (源碼能夠看出,發送空消息就能夠打斷該循環,終止該線程)spa
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 final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long traceTag = me.mTraceTag; if (traceTag != 0) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } 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.recycleUnchecked(); } }
二.Handler線程
重要的構造方法:code
- 傳入某個線程thread的Looper對象;這樣這個Handler就是該thread的Handler了(和在該thread的run方法中直接new一個沒有參數的Handler的效果是同樣的;可是在外部定義可使咱們更好使用)
/** * Use the provided {@link Looper} instead of the default one. * * @param looper The looper, must not be null. */ public Handler(Looper looper) { this(looper, null, false); } /** * Default constructor associates this handler with the {@link Looper} for the * current thread. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. */ public Handler() { this(null, false); }
三.MessageQueue對象
MessagerQueue是一個單向鏈表
HandlerThread
HandlerThread是Android系統本身實現的一個能夠實現 處理異步消息 的線程。簡單來講就是和UI線程是同樣的原理,經過Looper和Message通訊,讓該線程爲咱們服務。
具體能夠看源碼就能知道他的原理(咱們本身也能夠寫這樣的線程,可是系統給咱們的老是要好一點的)
@Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }
HandlerThread的使用
HandlerThread workThread = new HandlerThread(); workThread.start(); Handler handler = new Handler(workThread.getLooper());