Handler
Android 異步消息處理機(jī)制 ,Handle機(jī)制其實(shí)也為我們提供了異步消息處理機(jī)制代碼的參考冯痢。
由于Android系統(tǒng)規(guī)定主線程不能被阻塞渴频,所以耗時(shí)操作必須放在子線程中進(jìn)行儿捧。但是子線程中又不能訪問UI。
Handler解決了在子線程中無(wú)法訪問UI的矛盾昙衅。
使用
public void onClick(View v){
new Thread(new Runnable() {
@Override
public void run() {
//拿到Message對(duì)象
Message msg = Message.obtain();
msg.arg1 = 1;
mHandler.sendMessage(msg);
}
}) .start();
}
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//更新ui
TextView.setText("msg = " + msg.arg1);
}
};
實(shí)現(xiàn)消息驅(qū)動(dòng)有幾個(gè)要素:
- 消息的表示:Message
- 消息隊(duì)列:MessageQueue
- 消息循環(huán)煞檩,用于循環(huán)取出消息進(jìn)行處理:Looper
- 消息處理粘招,消息循環(huán)從消息隊(duì)列中取出消息后要對(duì)消息進(jìn)行處理:Handler
源碼分析
使用Handler之前啥寇,我們都是通過new Handler()初始化一個(gè)實(shí)例,同時(shí)會(huì)獲取Looper和messageQueue的實(shí)例洒扎。
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
//檢測(cè)擴(kuò)展此Handler類并且不是靜態(tài)的匿名辑甜,本地或成員類。 這些類可能會(huì)產(chǎn)生泄漏袍冷。
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());
}
}
//默認(rèn)將關(guān)聯(lián)當(dāng)前線程的looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//直接把關(guān)聯(lián)looper的MQ作為自己的MQ磷醋,因此它的消息將發(fā)送到關(guān)聯(lián)looper的MQ上
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
Handler的send或者post類方法被調(diào)用時(shí),最終會(huì)調(diào)用MessageQueue的enqueueMessage方法胡诗,將消息放入消息隊(duì)列中邓线。(post(Runnable r)中的Runnable對(duì)象會(huì)被封裝成message對(duì)象)
//發(fā)送消息
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}
//發(fā)送消息
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//最終都是調(diào)用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;//meg.target賦值為當(dāng)前handler
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//調(diào)用enqueueMessage()將Message送到MessageQueue中去,該MessageQueue的實(shí)例是looper在初始化的時(shí)候創(chuàng)建的
return queue.enqueueMessage(msg, uptimeMillis);
}
當(dāng)Looper發(fā)現(xiàn)有新消息來時(shí)煌恢,就會(huì)處理這個(gè)消息(Android 在進(jìn)程的入口函數(shù) ActivityThread.main()方法中骇陈,會(huì)調(diào)用 Looper.prepareMainLooper(), 為應(yīng)用的主線程創(chuàng)建Looper,然后調(diào)用Looper.loop()就啟動(dòng)了進(jìn)程的消息循環(huán)瑰抵。所以我們?cè)赼ctivity中創(chuàng)建的Handler默認(rèn)是運(yùn)行在ui線程中的你雌,可以直接更新ui。我們也可以在自線程中去調(diào)用Looper.prepare()方法去創(chuàng)建該線程的Looper)
//
public static final void prepare() {
//一個(gè)線程中只有一個(gè)Looper實(shí)例
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(true));
}
//輪詢處理調(diào)用handler.
public static void loop() {
final Looper me = myLooper();//獲取ThreadLocal中存儲(chǔ)的Looper實(shí)例
//需要先調(diào)用prepare()創(chuàng)建Looper實(shí)例
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;//獲取該looper實(shí)例中的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();
//無(wú)限循環(huán)
for (;;) {
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
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
//把消息交給msg.target的dispatchMessage方法去處理
//msg.target 是handler中enqueueMessage()方法中msg.target = this賦值的handler實(shí)例
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
//釋放資源
msg.recycleUnchecked();
}
}
looper輪詢處理消息調(diào)用dispatchMessage()方法
// 處理消息婿崭,該方法由looper調(diào)用
public void dispatchMessage(Message msg) {
// 如果message設(shè)置了callback,即runnable消息肴颊,處理callback氓栈!
if (msg.callback != null) {
handleCallback(msg);
} else {
// 如果handler本身設(shè)置了callback,則執(zhí)行callback
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//調(diào)用handleMessage()方法婿着,內(nèi)部是空實(shí)現(xiàn)授瘦,交給用戶復(fù)寫幸海,處理消息。
handleMessage(msg);
}
}
// 處理runnable消息
private final void handleCallback(Message message) {
message.callback.run(); //直接調(diào)用run方法
}
// 由用戶復(fù)寫
public void handleMessage(Message msg) {
}
Message
在整個(gè)消息處理機(jī)制中奥务,message封裝了任務(wù)攜帶的信息和處理該任務(wù)的handler物独。
- 盡管Message有public的默認(rèn)構(gòu)造方法,但是推薦通過Message.obtain()來從消息池中獲得空消息對(duì)象氯葬,以節(jié)省資源挡篓。
- 如果你的message只儲(chǔ)存int信息,優(yōu)先使用Message.arg1和Message.arg2來傳遞信息帚称,這比用Bundle更省內(nèi)存
- 擅用message.what來標(biāo)識(shí)信息官研,以便用不同方式處理message。