1. Android 消息機(jī)制概述
閱讀本文之前,你需要知道一下幾點(diǎn):
1.Handler的使用必須依賴于一個(gè)Looper對(duì)象
2.線程是默認(rèn)沒(méi)有Looper的,但是UI線程有一個(gè)Looper對(duì)象;
3.在啟動(dòng)APP的時(shí)候,UI線程Looper會(huì)初始化完畢,所以可以得出,UI線程可以直接使用Handler。
1.1Android消息機(jī)制是什么?
Android消息機(jī)制 主要指Handler的運(yùn)行機(jī)制以及Handler所附帶的MessageQueue和Looperde的工作流程。Handler的主要作用是將任務(wù)切換到指定線程去執(zhí)行,我們常用的就是通過(guò)Handler來(lái)異步更新UI(線程間的信息傳遞)。
1.2Android消息機(jī)制架構(gòu)

圖片來(lái)自http://wangkuiwu.github.io/2014/08/26/MessageQueue/
侵圖刪!
(01) Looper是消息循環(huán)類,它包括了mQueue成員變量;mQueue是消息隊(duì)列MessageQueue的實(shí)例。Looper還包含了loop()方法,通過(guò)調(diào)用loop()就能進(jìn)入到消息循環(huán)中。
(02) MessageQueue是消息隊(duì)列類,它包含了mMessages成員;mMessages是消息Message的實(shí)例。MessageQueue提供了next()方法來(lái)獲取消息隊(duì)列的下一則消息和enqueueMessage()插入消息。
(03) Message是消息類。Message包含了next,next是Message的實(shí)例;由此可見(jiàn),Message是一個(gè)單鏈表。Message還包括了target成員,target是Handler實(shí)例。此外,它還包括了arg1,arg2,what,obj等參數(shù),它們都是用于記錄消息的相關(guān)內(nèi)容。
(04) Handler是消息句柄類。Handler提供了sendMessage()來(lái)向消息隊(duì)列發(fā)送消息;發(fā)送消息的API有很多,它們的原理都是一樣的,這里僅僅只列舉了sendMessage()一個(gè)。 此外,Handler還提供了handleMessage()來(lái)處理消息隊(duì)列的消息;這樣,用戶通過(guò)覆蓋handleMessage()就能處理相應(yīng)的消息。
消息機(jī)制位于Java層的框架主要就有上面4個(gè)類所組成。在C++層,比較重要的是NativeMessageQueue和Loop這兩個(gè)類。
當(dāng)我們啟動(dòng)一個(gè)APK時(shí),ActivityManagerService會(huì)為我們的Activity創(chuàng)建并啟動(dòng)一個(gè)主線程(ActivityThread對(duì)象);在啟動(dòng)主線程時(shí),就會(huì)創(chuàng)建主線程對(duì)應(yīng)的消息循環(huán),并通過(guò)調(diào)用loop()進(jìn)入到消息循環(huán)中。當(dāng)我們需要往消息隊(duì)列發(fā)送消息時(shí),可以繼承Handler類,然后創(chuàng)建Handler類的實(shí)例;接著,通過(guò)該實(shí)例的sendMessage()方法就可以向消息隊(duì)列發(fā)送消息。 也就是說(shuō),主線程的消息隊(duì)列也一直存在的。當(dāng)消息隊(duì)列中沒(méi)有消息時(shí),消息隊(duì)列會(huì)進(jìn)入空閑等待狀態(tài);當(dāng)有消息時(shí),則消息隊(duì)列會(huì)進(jìn)入運(yùn)行狀態(tài),進(jìn)而將相應(yīng)的消息發(fā)送給handleMessage()進(jìn)行處理。
2.Android消息機(jī)制的引入
2.1 為什么需要Handler?
1.UI線程不能做耗時(shí)操作。
我們都知道,Android是只允許我們?cè)赨I線程更新UI,但是UI線程又不能做耗時(shí)的操作,所以,我們經(jīng)常會(huì)用到Handler來(lái)異步更新UI。
2.子線程不能訪問(wèn)UI。
如果所有的線程都能夠更改UI,將會(huì)造成UI處于不可預(yù)期的狀態(tài)。同時(shí)加鎖將會(huì)降低UI的訪問(wèn)效率。
基于此,Android提供了一種全新的方式來(lái)異步更新UI,在子線程進(jìn)行耗時(shí)操作,通過(guò)Handler的協(xié)作來(lái)完成主線程更新UI。
2.2 Handler來(lái)更新UI
step1: 在子線程發(fā)送Message
Message msg=handler.obtainMessage();
msg.obj=list;//發(fā)送了一個(gè)list集合
//sendMessage()方法,在主線程或者Worker Thread線程中發(fā)送,都是可以的,都可以被取到
handler.sendMessage(msg);
step 2:在主線程handleMessage
handler=new MyHandler();
class MyHandler extends Handler
{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.i(">>>>>>>",Thread.currentThread().getName());
list= (List<NewsBean.Second.Third>) msg.obj;//接收傳過(guò)來(lái)的集合
listView.setAdapter(new NewsListBaseAdapter(list,MainActivity.this));//更新UI
}
}
這是我們Handler的最簡(jiǎn)單的用法。
接下來(lái)我們?cè)僖赃@個(gè)例子為引入,進(jìn)行深入的源碼分析。
3.Android消息機(jī)制源碼解析
源碼分析基于8.0
我們都知道,線程默認(rèn)沒(méi)有Looper的,如果需要使用Handler就必須為線程創(chuàng)建Looper。我們經(jīng)常提到的主線程,也叫UI線程,它就是ActivityThread,ActivityThread被創(chuàng)建時(shí)就會(huì)初始化Looper,這也是在主線程中默認(rèn)可以使用Handler的原因。
這一點(diǎn)我們可以從源碼得知
ActivityThread.main()--表示源碼中ActivityThread類中的main方法,下同
public static void main(String[] args) {
6506 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
6507 SamplingProfilerIntegration.start();
6508
6509 // CloseGuard defaults to true and can be quite spammy. We
6510 // disable it here, but selectively enable it later (via
6511 // StrictMode) on debug builds, but using DropBox, not logs.
6512 CloseGuard.setEnabled(false);
6513
6514 Environment.initForCurrentUser();
6515
6516 // Set the reporter for event logging in libcore
6517 EventLogger.setReporter(new EventLoggingReporter());
6518
6519 // Make sure TrustedCertificateStore looks in the right place for CA certificates
6520 final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
6521 TrustedCertificateStore.setDefaultUserDirectory(configDir);
6522
6523 Process.setArgV0("<pre-initialized>");
6524
6525 Looper.prepareMainLooper();
6526
6527 ActivityThread thread = new ActivityThread();
6528 thread.attach(false);
6529
6530 if (sMainThreadHandler == null) {
6531 sMainThreadHandler = thread.getHandler();
6532 }
6533
6534 if (false) {
6535 Looper.myLooper().setMessageLogging(new
6536 LogPrinter(Log.DEBUG, "ActivityThread"));
6537 }
6538
6539 // End of event ActivityThreadMain.
6540 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
6541 Looper.loop(); //開(kāi)始循環(huán)
6542
6543 throw new RuntimeException("Main thread loop unexpectedly exited");
6544 }
通常在新打開(kāi)一個(gè)APK界面時(shí),系統(tǒng)會(huì)為APK啟動(dòng)創(chuàng)建一個(gè)ActivityThread對(duì)象,并調(diào)用它的main()方法。該main函數(shù)主要做了兩件事:(01),新建ActivityThread對(duì)象。 (02),使用主線程進(jìn)入消息循環(huán)。
3.1 發(fā)送消息
1.Message msg=handler.obtainMessage();
首先我們通過(guò)obtainMessage()方法獲取Message的實(shí)例。
Handler.obtainMessage()
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();//sPool為Message實(shí)例化對(duì)象,當(dāng)sPool為空時(shí),我們通過(guò)new實(shí)例化。
}
2.handler.sendMessage(msg);
通過(guò)handler發(fā)送Message。
Handler.sendMessage(msg)
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
調(diào)用sendMessageDelayed(msg, 0)方法,第二個(gè)參數(shù)為延遲時(shí)間,如果不帶參數(shù)延遲為0;
Handler.sendMessageDelayed
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
調(diào)用sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis),
Handler.sendMessageAtTime
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;//獲取MessageQueue實(shí)例
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);
}
這里我們通過(guò)全局變量賦值給MessageQueue 實(shí)例,這里只有MessageQueue實(shí)例不為空的時(shí)候我們才會(huì)去添加Message。我們看看mQueue是在哪里賦值的。
我們?cè)贖andler中找到了他的構(gòu)造方法
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;//給MessageQueue實(shí)例化
mCallback = callback;
mAsynchronous = async;
}
我們可以看到這個(gè)有參的構(gòu)造函數(shù)通過(guò) mQueue = mLooper.mQueue;進(jìn)行實(shí)例化。
Handler
public Handler() {
this(null, false);
}
而我們初始化Handler的時(shí)候不管是通過(guò)繼承Handler還是匿名CallBack接口的都會(huì)調(diào)用Handler(Callback callback, boolean async) 方法,所以,我們實(shí)例化Handler的時(shí)候就會(huì)實(shí)例化MessageQueue。
mLooper 是Looper的一個(gè)實(shí)例化對(duì)象,我們?nèi)ooper.java看看mQueue的初始化。
在Looper的構(gòu)造方法中找到了mQueue的初始化。
Looper
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);//初始化Looper的時(shí)候就會(huì)初始化MessageQueue
mThread = Thread.currentThread();
}
我們前面有提到,使用Handler之前一定要初始化一個(gè)Looper,而這里可以看到,初始化Looper的時(shí)候也會(huì)初始化MessageQueue。我們可以通過(guò)兩個(gè)方法來(lái)創(chuàng)建Looper,
分別是prepareMainLooper()和prepare()。
prepareMainLooper()是給UI線程使用的,我們?cè)谇懊娴姆治鲆呀?jīng)知道,ActivityThread被創(chuàng)建時(shí)就會(huì)初始化Looper,就已經(jīng)調(diào)用了prepareMainLooper()方法,我們看看prepareMainLooper()的實(shí)現(xiàn):
Looper.prepareMainLooper()
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);//還是調(diào)用Prepare方法
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();//return sThreadLocal.get();通過(guò)ThreadLocal返回一個(gè)Looper
}
}
我們可以看到這個(gè)方法的注釋,也是將當(dāng)前線程作為一個(gè)Looper。
我們?cè)俳又磒repare()方法
Looper.prepare(boolean quitAllowed)
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");//不能多次創(chuàng)建
}
sThreadLocal.set(new Looper(quitAllowed));//將Looper存儲(chǔ)到ThreadLocal中
}
到這里我們可以看到Looper進(jìn)行了創(chuàng)建,并被保存到了ThreadLocal中。我們終于知道了在Looper創(chuàng)建的時(shí)候同時(shí)也會(huì)創(chuàng)建MessageQueue對(duì)象。
ThreadLocal: 線程本地存儲(chǔ)區(qū)(Thread Local Storage,簡(jiǎn)稱為TLS),每個(gè)線程都有自己的私有的本地存儲(chǔ)區(qū)域,不同線程之間彼此不能訪問(wèn)對(duì)方的TLS區(qū)域。我們會(huì)在后面詳細(xì)講解ThreadLocal。
回到前面的方法sendMessageAtTime(Message msg, long uptimeMillis),這個(gè)時(shí)候我們知道里面的queue(MessageQueue對(duì)象)不為空,然后返回return enqueueMessage(queue, msg, uptimeMillis);
MessageQueue.enqueueMessage
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;//this為當(dāng)前handler的對(duì)象
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
這里直接調(diào)用queue.enqueueMessage(msg, uptimeMillis);
由于queue是MessageQueue的對(duì)象,我們?nèi)essageQueue.java看看
enqueueMessage(msg, uptimeMillis)
MessageQueue.enqueueMessage(msg, uptimeMillis)
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {//mQuitting標(biāo)識(shí)Looper是否調(diào)用了quit()方法
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();//為了循環(huán)利用
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);//調(diào)用本地方法
}
}
return true;
}
這里主要是將消息加入消息隊(duì)列中,然后調(diào)用底層的方法。至此,我們sendMessage()已經(jīng)分析完了。
3.2 處理消息
我們繼續(xù)往下面分析,前面我們知道,UI線程在進(jìn)行Looper創(chuàng)建的時(shí)候會(huì)調(diào)用 Looper.loop();方法,而這個(gè)方法也是最重要的我們來(lái)看看他的源碼:
Looper.loop()
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper();//return sThreadLocal.get();通過(guò)ThreadLocal獲取當(dāng)前線程的Looper對(duì)象。
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;//獲取MessageQueue對(duì)象
// 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) {//沒(méi)有消息,則退出循環(huán)
// 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; //默認(rèn)為null,可通過(guò)setMessageLogging()方法來(lái)指定輸出,用于debug功能
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
final long end;
try {
msg.target.dispatchMessage(msg);//將message分發(fā)下去,target為當(dāng)前Handler對(duì)象
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (slowDispatchThresholdMs > 0) {
final long time = end - start;
if (time > slowDispatchThresholdMs) {
Slog.w(TAG, "Dispatch took " + time + "ms on "
+ Thread.currentThread().getName() + ", h=" +
msg.target + " cb=" + msg.callback + " msg=" + msg.what);
}
}
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();
}
}
loop方法小結(jié):
loop()進(jìn)入循環(huán)模式,不斷重復(fù)下面的操作,直到?jīng)]有消息時(shí)退出循環(huán)
讀取MessageQueue的下一條Message;
把Message分發(fā)給相應(yīng)的target;
再把分發(fā)后的Message回收到消息池,以便重復(fù)利用。
final Looper me = myLooper(),通過(guò)myLooper()方法獲取當(dāng)前線程的Looper對(duì)象
Looper.myLooper()
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
這里我們通過(guò)ThreadLocal.get()來(lái)獲取Looper對(duì)象,前面我們通過(guò)prepare()方法進(jìn)行了set,這里通過(guò)get()方法獲取出來(lái)。
這里我們主要看 msg.target.dispatchMessage(msg);
Handler.dispatchMessage(msg)
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {//是一個(gè)Runnable對(duì)象,實(shí)際就是Handler的post方法所傳遞的Runnable參數(shù)
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);//處理消息
}
}
這里調(diào)用了handlMessage(msg)方法處理消息;
Handler.handlMessage(msg)
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
到這里是不是恍然大悟,沒(méi)錯(cuò),這個(gè)就是我們前面重寫的方法。注釋也很清楚,子類必須重寫這個(gè)方法。
到這里,我們就已經(jīng)理清了所有的流程了。
4.附加知識(shí)
4.1ThreadLocal
前面由于在分析整個(gè)流程,怕影響思路,所以把ThreadLocal放到這里來(lái)講。
ThreadLocal: 線程本地存儲(chǔ)區(qū)(Thread Local Storage,簡(jiǎn)稱為TLS),每個(gè)線程都有自己的私有的本地存儲(chǔ)區(qū)域,不同線程之間彼此不能訪問(wèn)對(duì)方的TLS區(qū)域。
前面我們知道,
Looper的prepare()方法會(huì)調(diào)用ThreadLocal.set(T value)
Looper的loop()方法會(huì)調(diào)用ThreadLocal.get().
ThreadLocal.set(T value):將value存儲(chǔ)到當(dāng)前線程的TLS區(qū)域,源碼如下:
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);//將Looper存儲(chǔ)到ThreadLocalMap
else
createMap(t, value);
}
ThreadLocal.get():獲取當(dāng)前線程TLS區(qū)域的數(shù)據(jù),源碼如下:
/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;//獲取前面存儲(chǔ)的Looper
}
}
return setInitialValue();
}
5.總結(jié)
1.UI線程默認(rèn)會(huì)有一個(gè)Looper
2.Looper通過(guò)ThreadLocal的set和get方法進(jìn)行設(shè)置和獲取
3.初始化的Handler的時(shí)候同時(shí)會(huì)初始化一個(gè)MessageQueue,Handler必須依賴于一個(gè)Looper;
4.Looper 中的loop方法非常的重要,這是一個(gè)循環(huán)監(jiān)聽(tīng)MessageQueue是否更新的方法。
5.當(dāng)有數(shù)據(jù)更新,則調(diào)用dispatchMessage()方法處理數(shù)據(jù),這個(gè)方法會(huì)調(diào)用回調(diào)方法handleMessage(Message msg)來(lái)處理消息。
6.Message是信息載體。
消息機(jī)制還有許多方法這里沒(méi)有進(jìn)行講解
如:
1.我們也可以通過(guò)Handler handler =new Handler(new CallBack)來(lái)創(chuàng)建handler
2.Looper.quit()方法退出循環(huán),當(dāng)然本質(zhì)還是通過(guò)MessageQueue.quit()方法。前面有提到一個(gè)mQuitting就是通過(guò)這個(gè)判斷的。
3.發(fā)送消息也可以通過(guò)post(Runnable r)方法
等等
需要你們自己去看源碼。
這里主要是通過(guò)一個(gè)簡(jiǎn)單的流程對(duì)源碼進(jìn)行解析。
參考:
Android開(kāi)發(fā)藝術(shù)探索
Android消息機(jī)制架構(gòu)和源碼解析
Android消息機(jī)制1-Handler(Java層)