轉載請註明出處:http://blog.csdn.net/lowprofile_coding/article/details/72580044 介紹 "前面的內容對Handler做了介紹,也講解瞭如何使用handler" ,但是我們並不知道他的實現原理。本文從源碼的角度來分析如何實現的。 首先我們得 ...
轉載請註明出處:http://blog.csdn.net/lowprofile_coding/article/details/72580044
介紹
前面的內容對Handler做了介紹,也講解瞭如何使用handler,但是我們並不知道他的實現原理。本文從源碼的角度來分析如何實現的。
首先我們得知道Handler,Looper,Message Queue三者之間的關係
- Handler封裝了消息的發送,也負責接收消。內部會跟Looper關聯。
- Looper 消息封裝的載,內部包含了MessageQueue,負責從MessageQueue取出消息,然後交給Handler處理
- MessageQueue 就是一個消息隊列,負責存儲消息,有消息過來就存儲起來,Looper會迴圈的從MessageQueue讀取消息。
源碼分析
當我們new一個Handler對象的時候,看看他的構造方法裡面做了什麼.
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;
}
從源碼中我們看到他會調用Looper.myLooper方法獲取一個Looper對象,然後從Looper對象獲取到MessageQueue對象。
Looper myLooper()
跟進去看看Looper.myLooper()方法做了什麼。這是一個靜態方法,可以類名.方法名直接調用。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
這個方法裡面就一行代碼,從sThreadLocal中獲取一個Looper對象,sThreadLocal是一個ThreadLocal對象,可以在一個線程中存儲變數。底層是ThreadLocalMap,既然是Map類型那肯定得先set一個Looper對象,然後我們才能從sThreadLocal對象裡面get一個Looper對象。
ActivityThread main()
說到這裡得給大家介紹一個新的類ActivityThread,ActivityThread類是Android APP進程的初始類,它的main函數是這個APP進程的入口。我們看看這個main函數幹了什麼事情。
public static final void main(String[] args) {
------
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
-----
}
在第二行代碼調用Looper.prepareMainLooper()方法,第13行調用了Looper.loop()方法。
Looper prepareMainLooper()
繼續跟進Looper.prepareMainLooper()方法,在這個方法中第一行代碼調用了內部的prepare方法。prepareMainLooper有點像單例模式中的getInstance方法,只不過getInstance會當時返回一個對象,而prepareMainLooper會新建一個Looper對象,存儲在sThreadLocal中。
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
Looper prepare()
繼續跟進prepare方法,看第5行代碼,新建了一個Looper對象,調用sThreadLocal.set方法把Looper對象保存起來。看到這裡我想聰明的你們肯定明白了為什麼new Handler對象的時候調用Looper.myLooper()方法能從sThreadLocal對象中取到Looper對象。
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內部包含了MessageQueue,其實就是在new Looper對象的時候就new了一個MessageQueue對象。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Looper loop()
ActivityThread類main方法中調用了Looper的兩個方法,前面我們解釋了prepareMainLooper(),現在來看第二個方法loop()。
public static void loop() {
final Looper me = myLooper();//獲取Looper對象
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;//從Looper對象獲取MessageQueue對象
// 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 (;;) {//死迴圈 一直從MessageQueue中遍歷消息
Message msg = queue.next(); // might block
if (msg == null) {
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.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
//調用handler的dispatchMessage方法,把消息交給handler處理
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();
}
}
這個方法的代碼呢比較多。我都給代碼加上了註釋。其實就是一個死迴圈,一直會從MessageQueue中取消息,如果取到了消息呢,會執行msg.target.dispatchMessage(msg)這行代碼,msg.target就是handler,其實就是調用handler的dispatchMessage方法,然後把從MessageQueue中取到的message傳入進去。
Handler dispatchMessage()
public void dispatchMessage(Message msg) {
//如果callback不為空,說明發送消息的時候是post一個Runnable對象
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {//這個是用來攔截消息的
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);//最終調用我們重寫的handleMessage方法
}
}
這個方法對消息做最後處理,如果是post類型調用handleCallback方法處理,如果是sendMessage發送的消息。看我們有沒有攔截消息,如果沒有最終調用handleMessage方法處理。
Handler handleCallback()
看到這裡我們知道為什麼post一個Runnable對象,run方法執行的代碼在主線程了吧,因為底層根本就沒有開啟線程,就只是調用了run方法而已。
private static void handleCallback(Message message) {
message.callback.run();
}
前面我們從創建handler對象開始,以及創建Looper,創建MessageQueue的整個流程,現在來分析下,當我們調用post以及sendMessage方法時,怎麼把Message添加到MessageQueue。
Handler post()
調用了getPostMessage方法,把Runnable傳遞進去。
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
Handler getPostMessage()
首先調用Message.obtain()方法,取出一個Message對象,這個方法之前有講過,然後把Runnable對象賦值了Message對象的callback屬性。看到這裡我們也明白了dispatchMessage方法為什麼要先判斷callback是否為空了吧。
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
Handler enqueueMessage()
在post方法裡面調用了sendMessageDelayed方法,其實最終調用的是enqueueMessage方法,所以我這裡就直接看enqueueMessage方法源碼。第一行代碼就把handler自己賦值給messgae對象的target屬性。然後調用MessageQueue的enqueueMessage方法把當前的Messgae添加進去。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
總結
總結:handler負責發送消息,Looper負責接收Handler發送的消息,並直接把消息回傳給Handler自己。MessageQueue就是一個存儲消息的容器。
如果你想第一時間看我們的後期文章,掃碼關註公眾號,每周不定期推送Android開發實戰教程文章,你還等什麼,趕快關註吧,學好技術,出任ceo,贏取白富美。。。。
Android開發666 - 安卓開發技術分享
掃描二維碼加關註