android的handler、looper、Message之間的關係
handler:繫結到一個執行緒上,一個執行緒可以有多個handler
looper:執行緒跟looper是一一對應的,所以looper不能被呼叫兩次否則會丟擲異常
messge:handler利用message來攜帶訊息
messagQueue:用來狀態message,一個looper對應一個訊息佇列
如何來判斷一個訊息佇列對應一個handler呢,在sendmessage中獲取到一個訊息佇列的持有者looper
looper的兩個方法:prepare()和loop()
1.
public static final void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(true)); }
給當前執行緒一個設定一個looper例項
2.
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mRun = true; mThread = Thread.currentThread(); }
給這個looper建立一個訊息佇列(在建構函式中),並返回當前的執行緒
3.
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(); } }
public static Looper myLooper() { return sThreadLocal.get(); }
直接拿到該looper例項中的訊息佇列,然後迴圈每一個message(進入了無限迴圈),遍歷訊息之後會通過這個message的handler進行分發。
msg.target.dispatchMessage(msg); 中的target是handler
總結looper的主要作用
1) 與當前執行緒繫結,保證一個執行緒只會有一個Looper例項,同時一個Looper例項也只有一個MessageQueue。
2) loop()方法,不斷從MessageQueue中去取訊息,交給訊息的target屬性的dispatchMessage去處理。
handler
public Handler() { this(null, false); } public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
handler繫結到looper上,由於一個looper對一個一個訊息佇列,這樣這個handler就繫結到這個looper上了,也同時繫結到了這個執行緒上。
handler.sendMessgae()是用來講Message新增進訊息佇列的。。dispatchmessage才是用於分發的(如上looper介紹)
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
public void handleMessage(Message msg) { }
handleMessage此時是空的函式,需要我們之後的複寫
步驟:
1、首先Looper.prepare()在本執行緒中儲存一個Looper例項,然後該例項中儲存一個MessageQueue物件;因為Looper.prepare()在一個執行緒中只能呼叫一次,所以MessageQueue在一個執行緒中只會存在一個。 2、Looper.loop()會讓當前執行緒進入一個無限迴圈,不端從MessageQueue的例項中讀取訊息,然後回撥msg.target.dispatchMessage(msg)方法。 3、Handler的構造方法,會首先得到當前執行緒中儲存的Looper例項,進而與Looper例項中的MessageQueue想關聯。 4、Handler的sendMessage方法,會給msg的target賦值為handler自身,然後加入MessageQueue中。 5、在構造Handler例項時,我們會重寫handleMessage方法,也就是msg.target.dispatchMessage(msg)最終呼叫的方法。 6、handler也可以進行存在於子執行緒中,為什麼我們一般見到的都在主執行緒中呢?因為一般是針對UI空間更新的操作是不安全的所以handler放在主執行緒中,如果不存在這樣的業務,當