android的消息機制包括:handler(處理者)、looper(循環)、messageQueue(消息隊列)、message消息。
這裏先理解一個消息隊列這個概念,handler的消息隊列是先進先出的鏈表結構,下面是模擬消息隊列寫的一些方法。
消息類的寫法
public class MessageData {
//傳遞的數據類型,以作判斷
public int status;
//你需要處理的數據
public Object data;
//用於連接消息的類
public MessageData message;
//最多連接數,這裏沒做處理
public int linkedSize = 0;
}
消息隊列的寫法
public class MessageQueueData {
private MessageData messageData;
//入隊:將消息存入消息隊列中
public void enqueueMessage(MessageData messageData) {
Log.e("MessageQueueData", "enqueueMessage:" + messageData.status);
//判斷消息隊列是否爲空,如果爲空,就講鏈條的第一個消息置位假如的消息
if (this.messageData == null) {
this.messageData = messageData;
this.messageData.message = null;
} else {
//如果不爲空,進行鏈條循環,
//將鏈條的第一數據賦值
MessageData tempMy = this.messageData;
MessageData tempInner;
for (; ; ) {
//取出該數據中用於連接的數據
tempInner = tempMy.message;
//如果該數據不爲空,將該數據置爲鏈條的類
if (tempInner != null) {
tempMy = tempInner;
} else {
//如果該數據爲空,將該數據假如鏈條,結束循環
tempMy.message = messageData;
break;
}
}
}
}
//出隊,將消息從消息隊列中取出
public void next() {
if (this.messageData != null) {
Log.e("MessageQueueData", "next:" + this.messageData.status);
//取出消息,將內部連接到該類中
this.messageData = this.messageData.message;
}
}
}
執行過後的數據爲
這裏就體現出了先進先出的邏輯,好了,下面自定義一個looper循環的定時器
private class HandlerThread extends Thread {
private Handler mHandler;
private TimmerRunnable mTimmerRunnable;
private int time = 0;
public HandlerThread() {
mTimmerRunnable = new TimmerRunnable();
}
@Override
public void run() {
super.run();
//創建該線程的looper,一個線程只能創建一個looper
Looper.prepare();
//創建該線程的handler
mHandler = new Handler();
//發送消息,及消息入隊
mHandler.post(mTimmerRunnable);
//開始循環,進入循環獲取消息
Looper.loop();
}
public void stopThread() {
//退出循環,結束線程
mHandler.getLooper().quit();
}
private class TimmerRunnable implements Runnable {
@Override
public void run() {
//消息會送,在這裏處理你的消息,這樣就實現了一個消息循環了,完成定時器
time++;
tv_time.post(new Runnable() {
@Override
public void run() {
tv_time.setText("時間:" + time);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mHandler.post(mTimmerRunnable);
}
}
}
先從創建開始,這裏調用looper的prepare()
//先調用的這個方法
public static void prepare() {
prepare(true);
}
//做空判斷,如果該線程已近存在looper了就會拋出異常,所以一個線程只能有一個looper
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));
}
//創建消息隊列,將該線程賦值到looper中
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Handler的創建
//沒有傳入參數的構造方法
public Handler() {
this(null, false);
}
//調用的是該構造函數
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());
}
}
//獲取該線程的looper,如果該線程的looper不存在,就會拋出異常
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
//將looper創建的MessageQueue賦值到handler中
mQueue = mLooper.mQueue;
//消息處理接口,用於從消息隊列出去後發送回主界面,以便於實現你的代碼
mCallback = callback;
mAsynchronous = async;
}
接下來進入Looper的循環機制
//進入循環
public static void loop() {
//獲取該線程的looper,如果爲空則拋出異常
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//獲取looper中創建的消息隊列
final MessageQueue queue = me.mQueue;
// 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();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
boolean slowDeliveryDetected = false;
//進入死循環,循環讀取消息隊列中的消息
for (;;) {
//獲取消息隊列的消息,如果消息隊列返還爲空,則跳出循環結束該方法
//消息隊列中,當隊列中的消息問空的時候會進入死循環,這裏會進入阻塞狀態
//只用手動調用queue.quit()方法纔會返回空,然後結束該方法,結束線程
Message msg = queue.next(); // might block
if (msg == null) {
// 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;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
try {
//經過一些列的數據處理,當到達這裏的時候,將Message小心中的handler取出來
//然後調用handler的dispatchMessage方法,將消息進行分發
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
…………
//釋放Message,將Message數據重置,然後開始下一次消息的讀取
msg.recycleUnchecked();
}
}
消息隊列的數據讀取,出隊,MessageQueue.next方法
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
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) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
//賦值消息隊列首部的消息
Message msg = mMessages;
//判斷該消息和該消息保存的handler是
//如果該消息不爲空,但是該消息的handler爲空,進入
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
//賦值,將該消息賦值給prevMsg,同時取出該消息內部存儲的消息,
//賦值到msg中
prevMsg = msg;
msg = msg.next;
//滿足條件,則繼讀取下一個鏈條的數據
} while (msg != null && !msg.isAsynchronous());
}
//如果不爲空
if (msg != null) {
if (now < msg.when) {
//下一條消息還沒有準備好。設置一個超時,當它準備好時喚醒。
// Next message is not ready. Set a timeout to wake up when it is 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 (DEBUG) Log.v(TAG, "Returning message: " + msg);
//改變消息隊列該鏈條的狀態
msg.markInUse();
//返還該鏈條的數據
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
//手動調用quit方法,結束該方法,返還空,到looper.loop層,然後結束該線程
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
……………………
}
}
接下來是消息分發了,handler.dispatchMessage方法
/**
* Handle system messages here.
*/
//這裏是判斷調用的是handler的post方法還是sendMessage方法
public void dispatchMessage(Message msg) {
//取出保存在message的handler的callback方法,如果該保存了該方法,就調用回調的
//post方法中的
if (msg.callback != null) {
handleCallback(msg);
} else {
//如果調用的是sendMessage方法,就會調用handleMessage,需要在創建Handler中重新改方法
//收取數據
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
這樣就完成了出隊的所有流程了。
接下來是入隊,入隊分爲handler.post和handler.sendMessage兩種方法入隊
先討論handler.post方法
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
//創建Message
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
//進入到這個方法中
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);
}
//在這個方法中開始進入MessageQueue的入隊方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
下面是MessageQueue中的enqueueMessage方法
boolean enqueueMessage(Message msg, long when) {
//當message中沒有保存handler的時候拋出異常
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;
}
至此,hander的入隊出隊就完成了