這幾天由於比較空,仔細讀了下Handler,Looper,Message和MessageQueue的源代碼,再結合一些現有的資料(比如任玉剛的Android開發藝術探索),深入的理解了一下Android是如何進行線程切換,異步加載的。
在介紹之前,首先要對幾個主要類進行理解。
Looper類
Looper類比較簡單,主要只有2個操作
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的構造函數初始化Looper對象的,然後把looper對象賦值給ThreadLocal(這個類在下面會進行介紹)
和
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.recycleUnchecked();
}
}
//這個方法就是類似自旋鎖的形式,用死循環的形式,去不停的取Message,只要取到Message就調用msg.target.dispatchMessage(msg);
Handler類
有幾個構造函數
//無參數的構造函數,主要調用Handler(Callback callback, boolean async)這個函數,在這個2個參數的構造函數裏詳細講下
public Handler() {
this(null, false);
}
public Handler(Callback callback) {
this(callback, false);
}
//調用了public Handler(Looper looper, Callback callback, boolean async)
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
public Handler(boolean async) {
this(null, async);
}
//這裏的Callback是Handler裏的一個內部接口,如果外部類繼承了這個接口,可以把這個類作爲Handler的代理類,代替Handler去執行HandlerMessage的操作
然後 boolean async是用於判斷message每次send或者post的時候是否需要同步
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;
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
就用註釋主要講解下我們常用的幾個構造函數
我們一般在程序裏在主線程都使用 new Handler()的方式去獲得一個Handler的實例,因爲Looper.myLooper()得到的就是mainLooper。在子線程如果這麼調就會報錯
throw new RuntimeException(“No Looper; Looper.prepare() wasn’t called on this thread.”);
原來就是主線程會在線程啓動時調用prepareMainLooper()方法,去new 一個Looper的實例,但是子線程需要我們手動去實現一個Looper的實例
,需要調new Handler(Looper.getMainLooper())方法
然後Handler裏有幾個常用的方法
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
這2個方法的本質是一樣的都是調用了sendMessageDelayed方法
post(Runnable r)方法多執行了一步,就是把Runnable包裝成一個Message
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
這裏會生成一個Message,然後把Runnable作爲一個成員變量的形式賦值給message,至於爲什麼這麼做,會在下面Handler如何處理Message中講到
然後我們再跟着代碼走,
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
這裏看到sendMessageDelayed方法只是簡單的對delayMillis進行處理,如果小於0,就賦予0值。而sendMessageAtTime也只是對MessageQueue進行了非空判斷。最後把只是簡單的把message塞進了MessageQueue當中
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//這裏有一個我認爲比較聰明的做法,把Handler做爲一個target給Message,等Message取出來的時候,就能很輕鬆的獲得Handler的對象
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
這樣整個發送消息的過程就結束了
post/sendMessage->sendMessageDelayed->sendMessageAtTime->
enqueueMessage 主要流程就是把MessageQueue當中
然後再講下取的過程
Looper在取到Message後,會調用msg.target.dispatchMessage(msg)(就是上面說到Looper.loop()裏乾的事);
然後會調用
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
//這裏的msg.callback就是我們之前把Runbale賦值給Message時獲得的。
//如果你給msg設置了callback handlerMessage方法就會不執行, 如果遇到這個問題的同學就會明白爲什麼了
//然後會去判斷代理是否爲空,如果不爲空就讓代理去執行handlerMessage方法。
//只有上述2個條件都爲空纔會執行我們熟悉的HandlerMessage方法
這樣我們就能用Handler去執行我們之前在子線程希望UI線程乾的事情了,但是爲什麼這樣就切換到UI線程了,這個就跟ThreadLocal有關了和Looper有關了,會在下一章講明白
Message和MessageQueue在這就不多說,因爲代碼非常簡單,Message就是一個實體類和我們在平時定義的業務實體類一樣。
MessageQueue就是一個單向鏈表,插入和刪除消耗比較少。