Android是消息驅(qū)動(dòng)的,實(shí)現(xiàn)消息驅(qū)動(dòng)有幾個(gè)要素:
1、Message:消息,其中包含了消息ID,消息處理對(duì)象以及處理的數(shù)據(jù)等,由MessageQueue統(tǒng)一列隊(duì),終由Handler處理
2、處理者,負(fù)責(zé)Message的發(fā)送及處理。使用Handler時(shí),需要實(shí)現(xiàn)handleMessage(Message
msg)方法來對(duì)特定的Message進(jìn)行處理,例如更新UI等。
3、MessageQueue:消息隊(duì)列,用來存放Handler發(fā)送過來的消息,并按照FIFO規(guī)則執(zhí)行。當(dāng)然,存放Message并非實(shí)際意義的保存,而是將Message以鏈表的方式串聯(lián)起來的,等待Looper的抽取。
4、Looper:消息泵,不斷地從MessageQueue中抽取Message執(zhí)行。因此,一個(gè)MessageQueue需要一個(gè)Looper。
5、Thread:線程,負(fù)責(zé)調(diào)度整個(gè)消息循環(huán),即消息循環(huán)的執(zhí)行場所。獲取loop
Looper.loop();
Public staticvoidloop(){
finalLooperme=myLooper();
}
//返回和線程相關(guān)的looper
Public staticLoopermyLooper(){
returnsThreadLocal.get();
}
Android系統(tǒng)的消息隊(duì)列和消息循環(huán)都是針對(duì)具體線程的,一個(gè)線程可以存在(當(dāng)然也可以不存在)一個(gè)消息隊(duì)列和一個(gè)消息循環(huán)(Looper),特定線程的消息只能分發(fā)給本線程,不能進(jìn)行跨線程,跨進(jìn)程通訊。但是創(chuàng)建的工作線程默認(rèn)是沒有消息循環(huán)和消息隊(duì)列的,如果想讓該
線程具有消息隊(duì)列和消息循環(huán),需要在線程中首先調(diào)用Looper.prepare()來創(chuàng)建消息隊(duì)列,然后調(diào)用Looper.loop()進(jìn)入消息循環(huán)。 如下例所示:
class LooperThread
extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Messagemsg) {
// process incoming messageshere
}
};
Looper.loop();
}
}
這樣你的線程就具有了消息處理機(jī)制了,在Handler中進(jìn)行消息處理。
Activity是一個(gè)UI線程,運(yùn)行于主線程中,Android系統(tǒng)在啟動(dòng)的時(shí)候會(huì)為Activity創(chuàng)建一個(gè)消息隊(duì)列和消息循環(huán)(Looper)。詳細(xì)實(shí)現(xiàn)請(qǐng)參考ActivityThread.java文件
Android應(yīng)用程序進(jìn)程在啟動(dòng)的時(shí)候,會(huì)在進(jìn)程中加載ActivityThread類,并且執(zhí)行這個(gè)類的main函數(shù),應(yīng)用程序的消息循環(huán)過程就是在這個(gè)main函數(shù)里面實(shí)現(xiàn)的
public final class
ActivityThread {
......
public
static final void main(String[] args) {
......
Looper.prepareMainLooper();
......
ActivityThread
thread = new ActivityThread();
thread.attach(false);
......
Looper.loop();
......
thread.detach();
......
}
}
這個(gè)函數(shù)做了兩件事情,一是在主線程中創(chuàng)建了一個(gè)ActivityThread實(shí)例,二是通過Looper類使主線程進(jìn)入消息循環(huán)中
初始化消息隊(duì)列
class LooperThread
extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Messagemsg) {
// process incoming messageshere
}
};
Looper.loop();
}
}
主要是紅色標(biāo)明的兩句,首先調(diào)用prepare初始化MessageQueue與Looper,然后調(diào)用loop進(jìn)入消息循環(huán)。先看一下Looper.prepare。
public static void
prepare() {
prepare(true);
}
private static void
prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Onlyone Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
重載函數(shù),quitAllowed默認(rèn)為true,從名字可以看出來就是消息循環(huán)是否可以退出,默認(rèn)是可退出的,Main線程(UI線程)初始化消息循環(huán)時(shí)會(huì)調(diào)用prepareMainLooper,傳進(jìn)去的是false。使用了ThreadLocal,每個(gè)線程可以初始化一個(gè)Looper。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();//mPtr記錄native消息隊(duì)列的信息
}
在Looper初始化時(shí),新建了一個(gè)MessageQueue的對(duì)象保存了在成員mQueue中。MessageQueue的構(gòu)造函數(shù)是包可見性,所以我們是無法直接使用的,在MessageQueue初始化的時(shí)候調(diào)用了nativeInit,這是一個(gè)Native方法:
android_os_MessageQueue_nativeInit();
static jlong
android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
NativeMessageQueue*nativeMessageQueue = new NativeMessageQueue();//初始化native消息隊(duì)列
if (!nativeMessageQueue) {
jniThrowRuntimeException(env,"Unable to allocate native queue");
return 0;
}
nativeMessageQueue->incStrong(env);
returnreinterpret_cast(nativeMessageQueue);
}
在nativeInit中,new了一個(gè)Native層的MessageQueue的對(duì)象,并將其地址保存在了Java層MessageQueue的成員mPtr中,Android中有好多這樣的實(shí)現(xiàn),一個(gè)類在Java層與Native層都有實(shí)現(xiàn),通過JNI的GetFieldID與SetIntField把Native層的類的實(shí)例地址保存到Java層類的實(shí)例的mPtr成員中,比如Parcel。
再看NativeMessageQueue的實(shí)現(xiàn):
new
NativeMessageQueue();
NativeMessageQueue::NativeMessageQueue()
: mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
mLooper =Looper::getForThread(); //獲取TLS中的Looper對(duì)象
if (mLooper == NULL) {
mLooper = newLooper(false); //創(chuàng)建native層的Looper
Looper::setForThread(mLooper); //保存native層的Looper到TLS中
}
}
Looper::getForThread(),功能類比于Java層的Looper.myLooper();
Looper::setForThread(mLooper),功能類比于Java層的ThreadLocal.set();
NativeMessageQueue::NativeMessageQueue()
: mInCallback(false), mExceptionObj(NULL) {
mLooper = Looper::getForThread();
if (mLooper == NULL) {
mLooper = new Looper(false);
Looper::setForThread(mLooper);
}
}
在NativeMessageQueue的構(gòu)造函數(shù)中獲得了一個(gè)Native層的Looper對(duì)象,Native層的Looper也使用了線程本地存儲(chǔ)
發(fā)送消息
通過Looper.prepare初始化好消息隊(duì)列后就可以調(diào)用Looper.loop進(jìn)入消息循環(huán)了,然后我們就可以向消息隊(duì)列發(fā)送消息,消息循環(huán)就會(huì)取出消息進(jìn)行處理,在看消息處理之前,先看一下消息是怎么被添加到消息隊(duì)列的。
在Java層,Message類表示一個(gè)消息對(duì)象,要發(fā)送消息首先就要先獲得一個(gè)消息對(duì)象,Message類的構(gòu)造函數(shù)是public的,但是不建議直接new Message,Message內(nèi)部保存了一個(gè)緩存的消息池,我們可以用obtain從緩存池獲得一個(gè)消息,Message使用完后系統(tǒng)會(huì)調(diào)用recycle回收,如果自己new很多Message,每次使用完后系統(tǒng)放入緩存池,會(huì)占用很多內(nèi)存的,如下所示:
public static
Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}
public void recycle() {
clearForRecycle();
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
Message內(nèi)部通過next成員實(shí)現(xiàn)了一個(gè)鏈表,這樣sPool就了為了一個(gè)Messages的緩存鏈表。
消息對(duì)象獲取到了怎么發(fā)送呢,大家都知道是通過Handler的post、sendMessage等方法,其實(shí)這些方法最終都是調(diào)用的同一個(gè)方法sendMessageAtTime:
public boolean
sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = newRuntimeException(
this + "sendMessageAtTime() called with no mQueue");
Log.w("Looper",e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg,uptimeMillis);
}
sendMessageAtTime獲取到消息隊(duì)列然后調(diào)用enqueueMessage方法,消息隊(duì)列mQueue是從與Handler關(guān)聯(lián)的Looper獲得的。
private boolean
enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg,uptimeMillis);
}
enqueueMessage
接下來看一下是怎么MessageQueue的enqueueMessage。
final boolean
enqueueMessage(Message msg, long when) {
if (msg.isInUse()) {
throw newAndroidRuntimeException(msg + " This message is already in use.");
}
if (msg.target == null) {
throw newAndroidRuntimeException("Message must have a target.");
}
boolean needWake;
synchronized (this) {
if (mQuiting) {
RuntimeException e = newRuntimeException(
msg.target + "sending message to a Handler on a dead thread");
Log.w("MessageQueue",e.getMessage(), e);
return false;
}
msg.when = when;
Message p = mMessages;
if (p == null || when == 0 || when< p.when) {
// New head, wake up the eventqueue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middleof the queue.Usually we don't have towake
// up the event queue unlessthere is a barrier at the head of the queue
// and the message is theearliest asynchronous message in the queue.
needWake = mBlocked &&p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when
break;
}
if (needWake &&p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p== prev.next
prev.next = msg;
}
}
if (needWake) {
nativeWake(mPtr);
}
return true;
}
在enqueueMessage中首先判斷,如果當(dāng)前的消息隊(duì)列為空,或者新添加的消息的執(zhí)行時(shí)間when是0,或者新添加的消息的執(zhí)行時(shí)間比消息隊(duì)列頭的消息的執(zhí)行時(shí)間還早,就把消息添加到消息隊(duì)列頭(消息隊(duì)列按時(shí)間排序),否則就要找到合適的位置將當(dāng)前消息添加到消息隊(duì)列。
消息循環(huán)
消息隊(duì)列初始化好了,也知道怎么發(fā)消息了,下面就是怎么處理消息了,看Handler.loop函數(shù):
public static void
loop() {
final Looper me =myLooper();//從該線程中取出對(duì)應(yīng)的looper對(duì)象
if (me == null) {
throw new RuntimeException("NoLooper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;//取消息隊(duì)列對(duì)象...
// Make sure the identity of thisthread is that of the local process,
// and keep track of what that identitytoken actually is.
Binder.clearCallingIdentity();
final long ident =Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next();//?might?block取消息隊(duì)列中的一個(gè)待處理消息..
if (msg == null) {
// No message indicates thatthe message queue is quitting.
return;
}
// This must be in a localvariable, 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 courseof dispatching the
// identity of the thread wasn'tcorrupted.
final long newIdent =Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Threadidentity 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();
}
}
loop每次從MessageQueue取出一個(gè)Message,調(diào)用msg.target.dispatchMessage(msg),target就是發(fā)送message時(shí)跟message關(guān)聯(lián)的handler,這樣就調(diào)用到了熟悉的dispatchMessage,Message被處理后會(huì)被recycle。當(dāng)queue.next返回null時(shí)會(huì)退出消息循環(huán),接下來就看一下MessageQueue.next是怎么取出消息的,又會(huì)在什么時(shí)候返回null。
final Message next()
{
int pendingIdleHandlerCount = -1; // -1only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(mPtr,nextPollTimeoutMillis);
synchronized (this) {
if (mQuiting) {
return null;
}
// Try to retrieve the nextmessage.Return if found.
final long now =SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null &&msg.target == null) {
// Stalled by abarrier.Find the next asynchronousmessage in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null&& !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is notready.Set a timeout to wake up when itis ready.
nextPollTimeoutMillis =(int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next =msg.next;
} else {
mMessages =msg.next;
}
msg.next = null;
if (false)Log.v("MessageQueue", "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// If first time idle, then getthe number of idlers to run.
// Idle handles only run if thequeue is empty or if the first message
// in the queue (possibly abarrier) is due to be handled in the future.
if (pendingIdleHandlerCount< 0
&& (mMessages== null || now < mMessages.when)) {
pendingIdleHandlerCount =mIdleHandlers.size();
}
if (pendingIdleHandlerCount<= 0) {
// No idle handlers torun.Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers ==null) {
mPendingIdleHandlers = newIdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers =mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this codeblock during the first iteration.
for (int i = 0; i
final IdleHandler idler =mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null;// release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf("MessageQueue", "IdleHandler threwexception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, anew message could have been delivered
// so go back and look again for apending message without waiting.
nextPollTimeoutMillis = 0;
}
}
MessageQueue.next首先會(huì)調(diào)用nativePollOnce,然后如果mQuiting為true就返回null,Looper就會(huì)退出消息循環(huán)。