說到sendMessage,開發中用的比較多,是Handler的方法,而Handler的機制,在整個Android系統中的應用非常廣泛,當然,也是面試中經常問到的知識點,過一過源碼,在此梳理下,
首先,一般使用Handler代碼是這樣的,如下:
Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
Toast.makeText(MainActivity.this, (String)msg.obj, 0).show();
}
};
//發送消息
handler.sendMessage(msg);
那麼,整個機制的具體流程是怎樣的呢?先看下Handler
Handler.java
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
//...省略...
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;
}
我們經常使用Handler的默認構造函數,創建Handler對象,默認構造函數內,會調用帶參數的構造函數,顯然 ,這裏的callbcak,mCallback爲null,asyn,mAsynchronous
爲false,Looper的myLooper方法執行後,mLooper初始化完成,這裏,可以從mLooper中獲取對應的一個mQueue,也就是MessageQune
下面,就來了解下Looper的創建
1.Looper的創建:
Looper.java
private static Looper sMainLooper;
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
public static void prepare() {
prepare(true);
}
public static Looper myLooper() { return sThreadLocal.get(); }
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));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
看完這段,大致瞭解到,上面Handler的構造方法中,調用Looper的myLooper()方法來獲取Looper對象,myLooper()內部關係到sThreadLocal變量,通過get()方法得到Looper。同
時,我們發現在prepare(quitAllowed)的方法內部,sThreadLocal通過set設置了新的Looper實例來保存,這樣,我們知道了sThreadLocal實際上是用來存儲Looper對象的,並且是一
個線程只能對應一個Looper,如下:
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
註釋的含義大致是,只有我們調用了prepare()方法,sThreadLocal纔會返回Looper對象,否則爲null。那麼,我們可以這樣理解,prepare()的調用,能夠創建Looper對象,同時創
建了mQueue(MessageQune對象),而其內部調用prepare(quitAllowed),prepareMainLooper也調用了prepare(quitAllowed),而且,prepare()與prepareMainLooper()全部是public
static 修飾的,這說明,它們是專門供外部來調用從而獲取Looper對象的。事實果真是如此嗎?先來看下,省略部分無關代碼,如下:
ActivityThread.java
public static void main(String[] args) {
//...
Looper.prepareMainLooper();
//...
Looper.loop();
//...
}
的確,在ActivityThread中main方法執行了prepareMainLooper(),loop()也被執行,而main方法是系統調用,同時,也就是說,系統預先幫我們創建好了Looper對象,並且開
啓輪詢。至於prepare(),也有用到,我們可以在子線程中使用Looper.prepare(),Looper.loop(),創建自己的Looper。記住,一定要先prepare,要知道,巧婦難成無米之炊,
體會下吧。到此,Looper的創建過程以及基本瞭解。
接着來看loop()是內部是如何的
2.Looper的輪詢:
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
//...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
return;
}
//...
msg.target.dispatchMessage(msg);
//...
msg.recycleUnchecked();
}
}
我們注意到loop()的內部,先是獲取到Looper對象,通過Looper得到對應的MessageQune,也就是mQueue。
接下來是無限的循環,不斷的從mQueue消息隊列中取消息,如果沒有取到,消息爲null,不再向下執行,繼續循環取,一旦取到Message,就會通過Message的target,派發
消息,之後對已派發的Message進行回收
target實際上就是Handler,後面還會看到,在此說明下
關於消息的回收,是對消息的相關參數進行出廠設置,也就是,將參數設置爲null或者0,但是,消息對象還在,沒有銷燬,可以重複利用,這點也可以從Message的obtain()方
法驗證
好了,經過上面兩個步驟,我們的Looper創建好了,也開始工作了,儘管是系統幫忙的,但是我們可以發消息了,繼續看Message的發送過程
3.Handler發送消息到MessageQune:
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);
}
以上的過程是在Handler中完成的,消息發出後可以根據返回值,判斷是否發送成功,繼續看
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
//...
return queue.enqueueMessage(msg, uptimeMillis);
}
這裏是上面提到的target,是this,就是當前Handler對象,也就是說,Handler發送消息時,綁定了自己,爲什麼綁定自己呢?這跟誰污染誰治理的原則是一樣的,當然,沒那
麼嚴重,是誰發送消息,就是誰處理消息,始終唯一
接下倆,就是將Messager進行編隊,入列的過程
4.MessageQueue對Message入列:
MessageQueue.java
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) {
// 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);
}
}
return true;
}
可以看到,內部有個無限循環,爲什麼要無限循環呢?因爲MessageQune是很被動的,它不知道什麼時候會有消息要加入,纔會不斷循環,只要有Message消息進來,就會將
Message進行編隊,沒有就跳出循環。接下來,終於等到派發Message消息,如下:Message的消息分發到Handler
msg.target.dispatchMessage(msg);
這句代碼是在loop()中執行的,爲了說明,最終Message是派發給當初負責發送它的Handler對象的,有點物歸原主的含義,可以體會下
下面,看Handler如何回調handMessage的
5.Handler回調方法處理消息:
Handler.java
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
在Handler對象創建時,mCallBack爲null,callBack也爲null,消息派發後,就調用handMessage方法,
文章開頭,重寫的handMessage方法
Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
Toast.makeText(MainActivity.this, (String)msg.obj, 0).show();
}
};
經過上面的幾個過程,handMessage方法被調用,吐司最終展示在UI界面上
好啦,以上就是Handler、Looper、MessageQueue之間的關係描述,收拾下,吃飯了...