目錄:
Handler
Handler概述:
Handler並不是專門用來更新UI界面的,只不過日常開發中,開發者用來更新UI比較多.
Handler的主要作用是:將一個任務切換到某個指定線程進行執行.
Handler的主要目的是:爲了解決在子線程中無法更新UI界面的矛盾問題
Handler原理圖:
主線程中爲什麼可以直接創建Hanlder:
在非主線程中創建Handler的時候需要先調用Looper.prepare();創建Looper對象以及完成消息隊列的初始化,然 後創建Handler對象,最後,調用Looper.loop();開啓消息循環;
而在主線程中,App的入口,ActivityThread.main方法中:
public static void main(String[] args) {
// 不相干代碼
......
// 1.調用Looper.prepareMainLooper,其實也就是調用的Looper.loop,初始化Looper、MessageQueue等
Looper.prepareMainLooper();
// 2.創建ActivityThread的同時,初始化了成員變量Handler mH
ActivityThread thread = new ActivityThread();
thread.attach(false);
//
if (sMainThreadHandler == null) {
// 把創建的Handler mH賦值給sMainThreadHandler
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// 3.調用Looper.loop()方法,開啓死循環,從MessageQueue中不斷取出Message來處理
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
主線程不需要手動調用,是因爲系統在啓動App時,就幫我們調用了
Handler使用的兩種方式:
**一:post方式**Handler mHandler = new Handler();
mHandler.post(new Runnable() {
@Override
public void run() { }
});
二:Message方式
//主線程中創建Handler
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 處理返回的消息
}
};
//---------------------------------------------
//在子線程總調用Handler發送消息
Message msg = Message.obtain();
msg.what = MSG_SUB_TO_MAIN;
msg.obj = "這是一個來自子線程的消息";
// 2.發送消息
mHandler.sendMessage(msg);
Handler中構造函數
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;
...
}
- 在創建Handler對象的時候,在構造函數中首先會初始化Looper對象並獲取其中的MessageQueue消息隊列對象;
- 當創建Handler對象的線程中沒有初始化Looper對象的時候就會導致拋出異常
post,Message調用的原理
post方式調用首先會調用getPostMessage(r)方法;private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
在該方法中,創建一個Message對象,將需要執行的Runable對象設定爲callback
隨後,post方法就和Message方法一樣,都會調用sendMessageDelayed()方法
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
在該方法中對設定的延遲時長進行判斷,隨後都調用了sendMessageAtTime(方法);
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
- 在sendMessageAtTime()獲取了Looper中的MessageQueue對象
- 在enqueueMessage()中將Hnadler對象賦值給了msg.target,並且將傳入的Message對象進行了enqueueMessage入隊操作
Looper
Looper的構造函數
private Looper(boolean quitAllowed) {
...
mQueue = new MessageQueue(quitAllowed);
...
}
在創建的Looper的時候在Looper的構造函數中會首先初始化好一個MessageQueue用來保存需要處理的meassage,所以消息隊列在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));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Looper創建的時候調用prepare方法,每個線程中只允許存在一個Looper,所以在重複創建會導致異常,當首次創建完成後,會將該Looper對象存儲到sThreadLocal中,並且在構造函數中完成隊列MessageQueue的初始化
開啓Looper循環的loop()
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) {
// No message indicates that the message queue is quitting.
return;
}
...省略部分代碼
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...省略部分代碼
msg.recycleUnchecked();
}
}
-
在Looper中執行循環的是loop方法,在方法中是一個無限循環,其中就調用到了MessageQueue中的next方法,而next方法也是一個無效循環的方法,在沒有消息的時候就處於阻塞狀態,在有消息的時候就對消息進行返回並將該條消息從消息隊列中移除;所以綜合來說,Looper中的無線循環通過MessageQueue的next方法獲取到了消息.
-
唯一退出循環的判斷條件是next爲null,在什麼情況下next會返回null呢?當調用Looper的quit方法時,會調用MessageQueue中的quit或者quitSaffely,兩個退出方法二者的區別是一個立即退出,一個是將當前隊列狀態修改爲退出狀態,等任務執行完成之後退出,當消息隊列被標記爲退出狀態時,next會返回null;
-
在獲取消息隊列中的message對象後,會通過msg.target獲取到Handler對象,去調用Handler中的dispatchMessage(msg);方法
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();
}
在dispatchMessage方法中,首先會判斷Runnable對象是否爲空,假如我通過post方法封裝了需要執行的Runnable,那麼在此處就會通過handleCallback()進行執行;而不論有沒有,最終都會再執行Handler中的handleMessage()方法
MessgaeQueue工作原理:
MeassgaeQueue翻譯的爲消息隊列,但它實質上並不是一個消息隊列,它的內部是一個單鏈表的數據結構用來存儲數據,但其並不對數據進行處理.
MessgaeQueue主要用到的有兩個方法enqueueMessage和next,
enqueueMessage主要用來存儲數據,想單鏈表中插入一條數據,next則是向鏈表中取出一條數據,並從隊列中刪除,需要說明的一點是,在next內部是一個無線循環,當沒有消息的時候就處於阻塞狀態,在有消息的情況下就會進行返回並將該條消息從隊列中移除.