android進階(十)-----Android消息機制

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中去執行,即切換到主線程去執行,這個過程就是主線程的消息循環模型。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章