[轉]Handler的執行機制
目錄
一. Handler的主要作用
Handler的主要作用:在子執行緒中傳送訊息, 在主執行緒中更新UI。
二. Handler的基本使用
1. Handler.sendMessage(msg)
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
mTextView.setText(msg.obj + ""); //更新UI
}
};
//子執行緒傳送訊息
new Thread(new Runnable () {
@Override
public void run() {
Message message = new Message();
message.obj = "6666";
mHandler.sendMessage(message);
}).start();
2. Handler.post(msg)
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler();
//子執行緒傳送訊息
new Thread(new Runnable() {
@Override
public void run() {
mHandler.post(new Runnable() { //切換到主執行緒更新UI
@Override
public void run() {
mTextView.setText("123456");
}
});
}).start();
三. Handler的執行機制
1. Handler.sendMessage(msg)做了些什麼?
Handler.java裡面的方法(部分關鍵程式碼):
sendMessage()
→sendMessageDelayed()
→sendMessageAtTime()
→enqueueMessage
;
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;
...
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
...
return queue.enqueueMessage(msg, uptimeMillis);
}
從上面來看,Handler最終呼叫了MessageQueue.enqueueMessage()
注意:
msg.target = this;
,msg.target
表示當前物件Handler, 後面Looper.loop()
用到
MessageQueue.enqueueMessage()
boolean enqueueMessage(Message msg, long when) {
{
...
synchronized (this) {
...
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;
}
...
}
return true;
}
}
從程式碼中慢慢分析,我們可以得出結論:其實MessageQueue.enqueueMessage()
方法就是把傳進來的Message
訊息物件,按照時間順序、佇列的結構 儲存起來。
在這裡,我們並沒有看到Handler.handleMessage()
方法的執行,繼續往下看。
2. 從ActivityThread.main()分析
我們就不慢慢從問題引進來了,直奔主題。
public static void main(String[] args) {
Looper.prepareMainLooper(); //初始化
Looper.loop();
}
2.1 Looper.prepareMainLooper()
prepareMainLooper()→prepare()
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) { //如果進行第二次初始化,則報異常
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper(); //賦值
}
}
//有且只有一個ThreadLocal物件
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static void prepare(boolean quitAllowed) {
//進入ThreadLocal原始碼裡set()和get()可以看出,每個執行緒只儲存一個Looper物件
//所以每個執行緒只能呼叫一次prepare(),否則會拋異常
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//ThreadLocal儲存Looper物件
sThreadLocal.set(new Looper(quitAllowed));
}
注意:prepare()方法 這裡有2個關鍵點:
- sThreadLocal.set() 和 get()方法
- Looper.java構造方法new Looper().
1.ThreadLocal.java 的set()和get()
public T get() {
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
Object[] table = values.table;
int index = hash & values.mask;
if (this.reference == table[index]) {
return (T) table[index + 1];
}
} else {
values = initializeValues(currentThread);
}
return (T) values.getAfterMiss(this);
}
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
set()
:給當前執行緒賦值一個:Loop物件
get()
:獲取當前執行緒的Loop物件
2. Looper.java構造方法
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
主要初始化訊息佇列MessageQueue
,即:一個Loop
有一個MessageQueue
訊息佇列物件
總結:Looper.prepareMainLooper() 主要作用:
- 初始化
Looper.sThreadLocal.set(new Looper(quitAllowed))
- 初始化
MessageQueue
物件,new Loop()
對應一個MessageQueue
物件
2.2 Looper.loop();
下面是部分的關鍵程式碼
public static void loop() {
{
final Looper me = myLooper();
...
final MessageQueue queue = me.mQueue;
...
for (;;) {
Message msg = queue.next(); // might block
...
msg.target.dispatchMessage(msg);
...
msg.recycle();
}
}
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
程式碼裡面都有註釋,最核心程式碼是msg.target.dispatchMessage(msg)
,msg.target
就是當前的Handler
物件,
接下來我們來看Handler.dispatchMessage()
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
這裡就執行了handleMessage()
方法
2.3 資源回收處理 msg.recycle()
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
public void recycle() {
clearForRecycle();
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
結論:Msg 物件範圍0到50個
最後圖解,如下圖:
程式碼分析基於kk