android消息机制主要是指Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑。
一、android消息机制概述
Handler创建时采用当前线程的Lopper来构建内部的消息循环,如果当前线程没有Lopper,就会报错。
Handler创建完成后,内部的Looper以及MessageQueue就可以和Handler协同工作了,通过Handler的post方法将一个Runnable投递到Handler内部的Lopper中去处理,也可以通过Handler的send方法发送一个消息,这个消息会在Looper中去处理。当send方法被调用时,他会调用MessageQueue的enqueueMessage方法将这个消息放入MessageQueue中,Looper发现有新消息到来,就会处理这个消息,最终消息的Runnable或者Handler的handleMessage方法会被调用
二、Android的消息机制分析
1、MessageQueue的工作原理
消息队列主要包含两个操作:插入和读取。
读取操作本身会伴随着删除操作,插入和读取对应的方法分别为:enqueueMessage和next。
下面看一下源码:
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) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
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;
}
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
从enqueueMessage的实现来看,他主要操作就是单链表的插入操作。
下面看next方法的逻辑:
Message next() {
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
nextPollTimeoutMillis = -1;
}
if (mQuitting) {
dispose();
return null;
}
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
for (int i = 0; i < pendingIdleHandlerCount; 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(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
可以发现next方法是一个无限循环的方法,如果消息队列中没有消息,那么next方法会一直阻塞在这里,有新消息时,next方法会返回这条消息并将其从单链表删除
2、Looper的工作原理
Looper会不停的从MessageQueue中查看是否有新消息,如果有就立刻处理,否则阻塞在哪里
首先看一下他的构造方法,在构造方法中会创建一个MessageQueue,然后将当前线程的对象保存起来,如下所示:
private Looper(boolean quitAllowed){
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
我们知道,Handler的工作需要Looper,没有Looper线程会报错,如何创建一个Looper哪,通过Looper.prepare()即可为当前线程创建一个Looper,接着通过Looper.loop()来开启消息循环,如下所示:
new Thread("thread2"){
@Override
public void run(){
Looper.prepare();
Handler handler = new Handler();
Looper.loop();
}
}.start();
Looper除了prepare方法外,还提供了prepareMainLooper方法,这个方法主要是给主线程创建Looper使用,本质也是通过prepare实现的
Lopper也是可以退出的,Looper提供了quit和quitSafely来退出一个looper,二者的区别:quit会直接退出Looper,而quitSafely只是设定一个退出标记,然后把消息队列中的已有消息处理完毕后再安全退出。looper退出后通过handler发送的消息会失败,handler的send方法会返回false。在子线程中如果手动创建了looper,那么在事情处理完成后应退出looper。
Looper最重要的方法是loop方法,只有调用loop后,消息循环系统才会真正起作用,源码如下:
public static void loop(){
final Lopper me = myLooper();
if(me == null){
throw new RuntimeException("No Looper;Looper.prepare() wasn ' t called on this thread")
}
final MessageQueue queue = me.mQueue;
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for(;;){
Message msg = queue.next();
if(msg == null){
return;
}
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);
}
final long newIdent = Binder.clearCallingIdentity();
if(iden != newIdent){
Log.wtf(TAG,"Thread identity changed form 0x"
+Long.toHexString(ident)+"to 0x"
+Long.toHexString(newIdent)+"while dispatching to"
+msg.target.getClass().getName()+""
+msg.callback+"what="+msg.what);
}
msg.recycleUnchecked();
}
}
loop方法是一个死循环,唯一跳出循环的方式MessageQueue的next方法返回null。当Looper的quit方法被调用时,Looper就会调用MessageQueue的quit或者quitSafely方法通知消息队列退出,当消息队列被标记为退出状态时,他的next方法就会返回null
3、Handler的工作原理
Handler的工作主要包含消息的发送和接受过程。消息的发送可以通过post的一系列方法以及send的一系列方法来实现,post的一系列方法最终是通过send的一系列方法来实现的。
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg,0);
}
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);
}
public boolean enqueueMessage(MessageQueue queue,Message msg,long uptimeMillis){
msg.target = this;
if(mAsynchronous){
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg,uptimeMillis);
}
Handler发送消息的过程仅仅是向消息队列中插入一条消息,MessageQueue的next方法就会返回这条消息给Looper,Looper收到消息后就开始处理了,最终消息由Looper交由Handler处理,即Handler的dispatchMessage方法会被调用,这个Handler就进入了处理消息的阶段。
dispatchMessage代码如下:
public void dispatchMessage(Message msg){
if(msg.callback != null){
handleCallback(msg);
}else {
if(mCallback != null){
if(mCallback.handleMessage(msg)){
return;
}
}
}
handleMessage(msg);
}
三、主线程的消息循环
Android的主线程就是ActivityThread,主线程的入口方法为main,在main方法中系统会通过Looper.prepareMainLooper()来创建主线程的Looper以及MessageQueue,并通过Looper.loop()来开启主线程的消息循环。
public static void main(String[] args){
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if(sMainThreadHandler == null){
sMainThreadHeadler = thread.getHandler();
}
AsyncTask.init();
if(false){
Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG,"ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
主线程的消息循环开始以后,ActivityThread还需要一个Handler来和消息队列进行交互,这个Handler就是ActivityThread.H,它内部定义了一组消息类型,主要包含了四大组件的启动和停止等过程,代码如下:
private class H extends Handler{
public static final int LAUNCH_ACTIVITY =100;
public static final int PAUSE_ACTIVITY =101;
public static final int PAUSE_ACTIVITY_FINISHING =102;
public static final int STOP_ACTIVITY_SHOW =103;
public static final int STOP_ACTIVITY_HIDE =104;
public static final int SHOW_WINDOW =105;
public static final int HIDE_WINDOW =106;
public static final int RESUME_ACTIVITY =107;
public static final int SEND_RESULT =108;
public static final int DESTROY_ACTIVITY =109;
public static final int BIND_APPLICATION =110;
public static final int EXIT_APPLICATION =111;
public static final int NEW_INTENT =112;
public static final int RECEIVER =113;
public static final int CREATE_SERVICE =114;
public static final int SERVICE_ARGS =115;
public static final int STOP_SERVICE =116;
......
}
ActivityThread通过ApplicationThread和AMS进行进程间通信。AMS以进程通信的方式完成ActivityThread的请求后会回调ApplicationThread中的Binder方法,然后ApplicationThread会向H发送消息,H接受到消息后会将ApplicationThread中的逻辑切换到ActivityThread中去执行,即切换到主线程去执行,这个过程就是主线程的消息循环模型。