Android 之 Handler ,Looper機制詳解
Handler 在日常開發中異步操作時經常使用到,接下來我們就來分析Handler機制,主要分爲兩大部分:
- 常見用法
- 源碼解讀
常見用法
一般我們會在Acticity或者其他地方中new一個Handler ,並重寫handleMessage的方法,在handleMessage中接受傳過來的消息:
private Handler mHandler = getLocalHandler();
private final static int FIRST_MESSAGE = 1;
private final static int SECOND_MESSAGE = 2;
public Handler getLocalHandler() {
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case FIRST_MESSAGE:
//doFirstThing();
break;
case SECOND_MESSAGE:
//doSecondThing();
break;
default:
break;
}
}
};
return handler;
}
然後可以在 其他的線程 或者 主線程 發消息給Handler,比如異步網絡加載完數據之後:
private void sendMessageToFirst() {
Message msg = new Message();
msg.obj = null;
//可用 msg.what 來區別並執行不同的事項
msg.what = FIRST_MESSAGE;
mHandler.sendEmptyMessage(FIRST_MESSAGE);
}
在 異步線程 或 主線程 我們也可以利用Handler來做延時處理操作:
private void sendMessageDelayed() {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
doSecondThing();
}
},2333);
}
上訴就是我們比較常規的用法。
源碼解讀篇
接下來我們來分析下Handler,Looper機制的java源碼
Handler(初始化):
首先看下new時Handler的構造器,代碼如下:
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
//...
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException("");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
可以看到,new時初始化 mLooper (Looper) ,mQueue (MessageQueue) ,mCallback (Callback) ,mAsynchronous (Boolean) 這四個對象。
下面我們逐一來分析他們:
Callback :
先說Callback,Callback是Handler類中的接口,其中的handleMessage與我們上述Handler重寫的handleMessage是一樣的方法名:
public interface Callback {
public boolean handleMessage(Message msg);
}
我們直接看他調用的地方,它在dispatchMessage方法中被使用,dispatchMessage(Message msg) 是處理消息的分發的方法,而方法中的 handleMessage(msg) ,它是我們執行 handler中 sendMessage,post(Runnable)等方法的執行語句
// dispatchMessage方法中被使用,dispatchMessage(Message msg)
// 是處理消息的分發的方法
public void dispatchMessage(Message msg) {
//..
// 這個爲callback
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//執行handler中 sendMessage,post等方法的分發執行語句
handleMessage(msg);
}
再看下callback調用的地方,可看到當 mCallback != null 且 mCallback.handleMessage(msg) 爲 true 的時候 return 方法不繼續往下走。不然執行handleMessage(msg),這說明我們在 handler 事件執行前多執行一些操作 或者 截斷handler事件的執行,所以可以使用下述的初始化Handler構造器,不過很少使用到這個。
//Handler.class
public Handler(Callback callback) {
this(callback, false);
}
Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
//可以在事件發送前自定義處理
// doSomeThing();
return false;
}
});
Looper:
接下來我們看下 mLooper 參數,它被賦值了 Looper.myLooper(),我們進Looper進去看,相關代碼貼下去:
static final ThreadLocal<Looper> sThreadLocal
= new ThreadLocal<Looper>();
public static Looper myLooper() {
return sThreadLocal.get();
}
可以看到是從 sThreadLocal 獲取一個Looper,使得且一個線程只有一個Looper,大家可以去網上搜索ThreadLocal的知識理解爲什麼線程只有一個Looper。在 get 之前肯定需初始化,我們找到初始化的地方,代碼如下:
private static Looper sMainLooper
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("");
}
sMainLooper = myLooper();
}
}
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();
}
在代碼中,我們可以看到新建了一個MessageQueue,我們進去看下:
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException(
"Main thread not allowed to quit.");
}
// ...
}
其中quitAllowed代表這個消息隊列是否可以停止,上訴可以看到賦值爲false時,調用quit()方法會報異常, 而mPtr是被底層c++使用,這個我們先不理。此時初始化已經分析完畢。
Handler機制(啓動):
在我們程序啓動時,系統會調用 prepareMainLooper() 方法,並初始化主線程的 Looper ,使主線程有可以使用的 Looper(),其中prepareMainLooper() 中 prepare(false) 會使Looper運行起來且不允許MessageQueue消息隊列中斷,這也可以理解不然在主UI中中斷了可就不好了,代碼如下:
// ActivityThread.class 主程序的入口
public static void main(String[] args) {
// ..
Looper.prepareMainLooper();
// ..
Looper.loop();
// ..
}
在上面可以看到在主程序開始時就就調用了prepareMainLooper()並使Looper loop()了起來,我們看下loop()方法,代碼如下 :
public static void loop() {
final Looper me = myLooper();
// ...
final MessageQueue queue = me.mQueue;
// ...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
return;
}
// ...
try {
msg.target.dispatchMessage(msg);
} finally {
// ...
}
// ...
msg.recycleUnchecked();
}
}
可以看到方法中,獲取當前MessageQueue對象,並開啓了死循環,當queue.next()消息隊列沒有消息就return繼續等待,有消息的話就往下執行 msg.target.dispatchMessage(msg) 語句。我們去先下queue.next()中的內容,代碼如下:
// MessageQueue.class
Message next() {
// 當loop被停止或者棄用 ptr 爲0
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
//...
// 下一次消息觸發時間
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;
// 如果同步時執行 且 msg.target == null執行
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;
msg.markInUse();
return msg;
}
} else {
nextPollTimeoutMillis = -1;
}
if (mQuitting) {
dispose();
return null;
}
}
//...
}
}
我們可以看到通過next()方法,我們可以獲取消息繼而執行,接着target是什麼,代碼如下:
// Message.class
Handler target;
可以看到 target 是個Handler對象,之前有稍微講下Handler的dispatchMessage()方法,讓我們再看一遍詳細代碼:
// Handler.class
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
public void handleMessage(Message msg) {
}
可以看到當傳下來的消息msg中的callback不爲空的時候,直接執行run()方法,不然就判斷mCallback 是否爲空且mCallback.handleMessage(msg)是否爲true,不然就執行我們重寫的handleMessage()方法。
那麼target又是哪裏賦值的呢,我們先看Message的構造器,代碼如下:
// Message.class
public Message() {
}
發現並沒有賦值target的值,我們回想一般在新建Message消息後我們會發送出來,我們去那個方法看下:
// Handler.class
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) {
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue,
Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
到最後我們可以發現target = this爲我們當前的Handler,最後我們看下enqueueMessage方法,代碼如下:
// MessageQueue.class
boolean enqueueMessage(Message msg, long when) {
//...
synchronized (this) {
if (mQuitting) {
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
// mMessages可以理解爲上一次Message
// 當mMessages不爲空,或者啓動時間爲0的,或者啓動時間小於mMessages的啓動時間
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;
prev.next = msg;
}
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
上述代碼就是Message插入隊列的代碼。
總結:
Handler機制其實在Android機制中算比較好理解的,我們可以看到主要涉及的類有Handler,Looper,MessageQueue和Message。
在主線程中,
Handler:負責對外,比如消息的添加,移除等功能,
Looper:個人理解作爲一個載體,承載着消息隊列的啓動,獲取及銷燬消息,使Handler不必對MessageQueue進行管理,專注處理對外事件的處理
MessageQueue:對消息的循環移除,及對C++代碼的通信。其中涉及到部分的jni代碼本篇暫時還沒解析,有興趣的同學可以自行了解或谷歌。
這也是本人的第一篇博客,如果有什麼寫的錯誤或者不足的,請大家留言幫忙糾錯!0-0