Looper主要有prepare()和loop()兩個(gè)方法榄笙,Looper是用來(lái)從MessageQueue中抽取Message邪狞,發(fā)送給Handler進(jìn)行處理。
prepare()方法:
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(true));
}
sThreadLocal是一個(gè)ThreadLocal對(duì)象茅撞,可以在一個(gè)線程中存儲(chǔ)變量帆卓。第一次調(diào)用prepare()方法,if條件不成立米丘,所以將創(chuàng)建的Looper對(duì)象保存到sThreadLocal中剑令。第二次調(diào)用就會(huì)拋出異常,說(shuō)明Looper.prepare()方法不能被調(diào)用兩次拄查,也保證了一個(gè)線程中只有一個(gè)Looper實(shí)例尚洽。
Looper的構(gòu)造方法:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread();
}
在構(gòu)造方法中,創(chuàng)建了一個(gè)MessageQueue(消息隊(duì)列)
loop()方法中調(diào)用myLooper()方法取出sThreadLocal中保存的Looper實(shí)例靶累,如果Looper實(shí)例為null則拋出異常腺毫,所以looper方法必須在prepare方法之后運(yùn)行。接著會(huì)獲取到該looper實(shí)例中的mQueue(消息隊(duì)列)挣柬。然后進(jìn)入了無(wú)限循環(huán)潮酒,從消息隊(duì)列中取出消息。調(diào)用 msg.target.dispatchMessage(msg);把消息交給msg的target的dispatchMessage方法去處理邪蛔,Msg的target就是handler對(duì)象急黎。
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
public static Looper myLooper() {
return sThreadLocal.get();
}
Handler的構(gòu)造方法中會(huì)調(diào)用Looper.myLooper()獲取了當(dāng)前線程保存的Looper實(shí)例,然后又通過(guò)mLooper.mQueue獲取了Looper實(shí)例中保存的MessageQueue(消息隊(duì)列)侧到,這樣就保證了handler的實(shí)例與我們Looper實(shí)例中MessageQueue關(guān)聯(lián)上了Handler的sendMessage(Message msg)方法最后調(diào)用了sendMessageAtTime()勃教,在此方法內(nèi)部直接獲取MessageQueue然后調(diào)用了enqueueMessage方法
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);
}
enqueueMessage方法中msg.target賦值為this,在Looper的loop方法會(huì)取出每個(gè)msg然后交給msg.target.dispatchMessage(msg)去處理消息匠抗,所以當(dāng)前的handler就是msg的target故源。最終調(diào)用queue的enqueueMessage的方法,也就是說(shuō)handler發(fā)出的消息汞贸,最終會(huì)保存到消息隊(duì)列中去绳军。不斷從MessageQueue中讀取Handler發(fā)來(lái)的消息,然后再回調(diào)創(chuàng)建這個(gè)消息的handler中的dispathMessage方法矢腻,在dispatchMessage方法中調(diào)用了handleMessage(msg)方法门驾,方法內(nèi)部是空實(shí)現(xiàn),因?yàn)橄⒌淖罱K回調(diào)是由我們控制的多柑,我們?cè)趧?chuàng)建handler的時(shí)候都是復(fù)寫handleMessage方法奶是,然后根據(jù)msg.what進(jìn)行消息處理
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
public void handleMessage(Message msg) {
}
注意:在Activity中,我們并沒(méi)有調(diào)用Looper.prepare()和Looper.loop()方法,但是Handler可以成功創(chuàng)建聂沙,這是因?yàn)樵贏ctivity的啟動(dòng)代碼中秆麸,已經(jīng)在當(dāng)前UI線程調(diào)用了Looper.prepare()和Looper.loop()方法
HandlerThread是Android API提供的一個(gè)便捷的類,使用它我們可以快速的創(chuàng)建一個(gè)帶有Looper的線程逐纬,有了Looper這個(gè)線程蛔屹,我們又可以生成Handler。HandlerThread本質(zhì)上是一個(gè)線程類豁生,它繼承了Thread兔毒;
HandlerThread有自己的內(nèi)部Looper對(duì)象,可以進(jìn)行l(wèi)ooper循環(huán)甸箱;
通過(guò)獲取HandlerThread的looper對(duì)象傳遞給Handler對(duì)象育叁,可以在handleMessage方法中執(zhí)行異步任務(wù)。
創(chuàng)建HandlerThread后必須先調(diào)用HandlerThread.start()方法芍殖,Thread會(huì)先調(diào)用run方法豪嗽,創(chuàng)建Looper對(duì)象
使用普通的Thread來(lái)創(chuàng)建一個(gè)Handler的過(guò)程:
Handler mHandler;
private void createThreadWithHandler() {
new Thread() {
@Override
public void run() {
super.run();
Looper.prepare();
mHandler = new Handler(Looper.myLooper());
Looper.loop();
}
}.start();
}
調(diào)用Looper.prepare 創(chuàng)建與當(dāng)前線程綁定的Looper實(shí)例
使用上面創(chuàng)建的Looper生成Handler實(shí)例
調(diào)用Looper.loop()實(shí)現(xiàn)消息循環(huán)
HandlerThread使用:
//傳入?yún)?shù)的作用主要是標(biāo)記當(dāng)前線程的名字,可以任意字符串
HandlerThread workerThread = new HandlerThread("LightTaskThread");
workerThread.start();
mHandler = new Handler(workerThread.getLooper());
注意:上面的workerThread.start()必須要執(zhí)行豌骏。
在activity的onDestory方法中調(diào)用workerThread.quit()方法結(jié)束當(dāng)前的Looper循環(huán)
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
從源碼可以看出HandlerThread繼續(xù)自Thread,構(gòu)造函數(shù)的傳遞參數(shù)有兩個(gè)龟梦,一個(gè)是name指的是線程的名稱,一個(gè)是priority指的是線程優(yōu)先級(jí)窃躲,我們根據(jù)需要調(diào)用即可计贰。其中成員變量mLooper就是HandlerThread自己持有的Looper對(duì)象。onLooperPrepared()該方法是一個(gè)空實(shí)現(xiàn)蒂窒,是留給我們必要時(shí)可以去重寫的躁倒,但是注意重寫時(shí)機(jī)是在Looper循環(huán)啟動(dòng)前
看看run方法:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
前面我們?cè)贖andlerThread的常規(guī)使用中分析過(guò),在創(chuàng)建HandlerThread對(duì)象后必須調(diào)用其start()方法才能進(jìn)行其他操作洒琢,而調(diào)用start()方法后相當(dāng)于啟動(dòng)了線程秧秉,也就是run方法將會(huì)被調(diào)用,而我們從run源碼中可以看出其執(zhí)行了Looper.prepare()代碼衰抑,這時(shí)Looper對(duì)象將被創(chuàng)建象迎,當(dāng)Looper對(duì)象被創(chuàng)建后將綁定在當(dāng)前線程(也就是當(dāng)前異步線程),這樣我們才可以把Looper對(duì)象賦值給Handler對(duì)象停士,進(jìn)而確保Handler對(duì)象中的handleMessage方法是在異步線程執(zhí)行的挖帘。
最近看到的一篇詳細(xì)分析線程池的文章,學(xué)習(xí)一下:
https://mp.weixin.qq.com/s/rHnzqlzJusIVNO7X7mBDkA