Handle在Android中的定位
1.所有的事件都是通過handle message 分發(fā)的。
通過launcher (app) 管理其他應(yīng)用APP的啟動拾给,利用zygote進(jìn)程兔沃,fork一個新進(jìn)程,分配jvm虛擬機(jī)(保證數(shù)據(jù)完整性窄锅,安全性)。每個java類追驴,都是通過一個main()函數(shù)啟動疏之,我們的應(yīng)用APP也是通過ActivityThread.main() 函數(shù)啟動,并且在此函數(shù)中丙曙,構(gòu)建了Looper實(shí)例對象其骄,執(zhí)行了Looper.loop() 函數(shù),用來不斷循環(huán)的取出消息拯爽。所以主線程中默認(rèn)有Looper毯炮,創(chuàng)建new Handle,不需要自定義Looper對象篮幢。
ActivityThread main()
public static void main(String[] args) {
....
Looper.prepareMainLooper(); //構(gòu)造Looper實(shí)例對象
.....
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler(); //返回 new handler()創(chuàng)建的實(shí)例對象
}
.....
Looper.loop(); //死循環(huán)为迈,輪播消息,分發(fā)給handle.handleMessage
....
}
Handle工作流程
1.子線程中 Handle發(fā)送消息
2.MessageQueue把消息加入隊(duì)列(MessageQueue只是一個容器赋续,沒有線程)
3.主線程 中的 Looper把消息從隊(duì)列中 取出來另患,分發(fā)給handle
4.handle在回調(diào)函數(shù)中 處理數(shù)據(jù)(主線程)
5.如此一個循環(huán)步驟昆箕,實(shí)現(xiàn)了線程之間的通信
源碼解析
1.handler 發(fā)送消息 ,最終會調(diào)到sendMessageAtTime--》enqueueMessage()
public boolean sendMessageAtTime(@NonNull 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(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
//msg消息 擁有handle,如果handle是內(nèi)部類鹏倘,那么有可能造成內(nèi)存泄露
msg.target = this;
....
return queue.enqueueMessage(msg, uptimeMillis);
}
2.MessageQueue enqueueMessage() 把消息加入隊(duì)列
MessageQueue 是個單鏈接優(yōu)先級隊(duì)列
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
synchronized (this) {//同步鎖薯嗤,保證數(shù)據(jù)隊(duì)列的線程安全
....
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
//判斷消息的優(yōu)先級,確定插入隊(duì)列位置
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; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) { //messageQueue為null時纤泵,進(jìn)入睡眠狀態(tài)
nativeWake(mPtr);
}
}
return true;
}
3.Looper .prepare() 構(gòu)建Looper實(shí)例對象骆姐,加入ThreadLocal
Looper .prepare() 構(gòu)造Looper()實(shí)例對象镜粤,Looper()是私有構(gòu)造函數(shù)
整個APP 只有一個ThreadLocal 對象實(shí)例,利用ThreadLocalMap存儲Looper實(shí)例肉渴,保證一個線程,只有一個Looper
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//sThreadLocal 存儲Looper實(shí)例的實(shí)現(xiàn)函數(shù)
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
//key是當(dāng)前線程带射,value是Looper實(shí)例同规,所以一個線程只有一個Looper
createMap(t, value);
}
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) { //一個線程只有一個Looper
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
//構(gòu)建 主線程的Looper,在ActivityThread.main()調(diào)用窟社,
//所以主線程new handle券勺,不需要對Looper進(jìn)行實(shí)例化
@Deprecated
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
//以thread為key,在ThreadLocalMap中取出存儲的Looper實(shí)例對象
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
/**
* 獲取主線程的Looper對象實(shí)例
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
4. Looper.loop() 循環(huán)遍歷messageQueue灿里,取出Message
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
...
for (;;) { //利用死循環(huán)关炼,循環(huán)取出messageQueue中的message,分發(fā)給handle的接口函數(shù)handleMessage()
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
Message msg = me.mQueue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return false;
}
...
try {
//調(diào)用handle dispatchMessage
msg.target.dispatchMessage(msg);
...
} catch (Exception exception) {
....
} finally {
.....
}
....
//對message進(jìn)行清空處理匣吊,復(fù)用內(nèi)存盗扒,避免內(nèi)存碎片,產(chǎn)生內(nèi)存抖動缀去,造成oom
msg.recycleUnchecked();
return true;
}
//messageQueue 通過next() 取出消息
Message next() {
final long ptr = mPtr;//是否進(jìn)入睡眠狀態(tài)
if (ptr == 0) {
return null;
}
......
for (;;) {
.....
synchronized (this) {
....
Message prevMsg = null;
Message msg = mMessages;
......
if (msg != null) {
....
} else {
......
return msg;
}
}
.....
if (mQuitting) { //Looper 調(diào)用了quit() 清空全部message信息
dispose();
return null;
}
..........
}
}
//handle dispatchMessage,把message 回調(diào)給handleMessage()函數(shù)
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
6.Message 類的 obtain(),享元設(shè)計(jì)模式,復(fù)用內(nèi)存
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
//message對象甸祭,數(shù)據(jù)清空缕碎,復(fù)用內(nèi)存
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
面試題解析
1.一個線程有幾個Handler?
可以有很多個Handler池户,在主線程中 new Handler(), 在子線程中 new Handle(Looper) 必須傳入對應(yīng)Looper對象咏雌。
2.一個線程有幾個Looper?怎么保證
一個線程只能有一個Looer校焦,通過ThreadLocal的ThreadLocalMap來保證赊抖,在Looper實(shí)例化的時候,會把Looper實(shí)例化對象存在ThreadLocalMap中寨典,key是當(dāng)前Thread氛雪。下次再調(diào)用Looper實(shí)例化函數(shù)prepare(),會先從ThreadLocalMap 讀取以thread為key的數(shù)據(jù),如果不為空耸成,拋出異常报亩。
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) { //一個線程只有一個Looper
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
3,Handler內(nèi)存泄露的原因井氢?為啥其他內(nèi)部類沒有這個問題弦追?
內(nèi)部類默認(rèn)持有外部類對象,所以handler實(shí)例默認(rèn)持有外部activity花竞。
在handler發(fā)送消息的函數(shù)中劲件,把handler對象賦值給了message,所以message持有了handler。而message的執(zhí)行是不確定的零远,按照順序執(zhí)行的苗分,如此一來即使activity退出頁面,也不會被內(nèi)存回收遍烦,造成內(nèi)存泄露俭嘁。可以使用靜態(tài)內(nèi)部 Handler來解決這個問題服猪。
其他內(nèi)部類 比如RecycleView adapter的viewHolder 為什么沒有造成內(nèi)存泄露供填,因?yàn)樗鴄ctivity的生命周期,當(dāng)activity退出罢猪,也會退出近她。
4.為何主線程可以直接new Handler(),子線程中想要new Handler()需要做哪些準(zhǔn)備?
Handler中必須有一個Looper對象膳帕。
因?yàn)橹骶€程在activityThread 的main()函數(shù)執(zhí)行的時候粘捎,就已經(jīng)創(chuàng)建了Looper的對象實(shí)例,并且調(diào)用了Loope.loop()函數(shù)危彩,所以不需要在對Looper對象操作攒磨。
想要在子線程中 new Handler()實(shí)例對象,必須初始化mLooper = Looper.prepar()構(gòu)建Looper實(shí)例對象汤徽,new Handler(mLooper) 創(chuàng)建handler對象娩缰,然后調(diào)用Looper.loop() 循環(huán)取出消息
5.子線程中維護(hù)的Looper,消息隊(duì)列無消息的時候的處理方案是什么谒府?有什么用拼坎?
消息隊(duì)列無消息的時候就進(jìn)入睡眠狀態(tài),Looper.loop死循環(huán)完疫,取出message 為null泰鸡,就退出本次循環(huán),然后再來一次壳鹤。Looper.quit()調(diào)用MessageQueue的quit()
//Looper.quit()
public void quit() {
mQueue.quit(false);
}
//MessageQueue的quit()
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked(); //清除所有的message數(shù)據(jù)
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr); //進(jìn)入睡眠狀態(tài)
}
private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {
Message n = p.next;
p.recycleUnchecked(); //清空數(shù)據(jù)盛龄,復(fù)用內(nèi)存
p = n;
}
mMessages = null;
}
}
6.存在多個Handler 往messageQueue 中添加數(shù)據(jù),內(nèi)部是如何確保線程安全的芳誓?
利用鎖來保證線程安全讯嫂,synchronized 同步鎖,也稱之為內(nèi)置鎖兆沙,有jvm實(shí)現(xiàn)上鎖和解鎖操作欧芽。
messageQueue.enqueueMessage(),利用 synchronized (this) 對整個messageQueue對象上鎖,對象里面的所有函數(shù) 代碼塊都會受到限制葛圃。并且一個線程中只有一個Looper千扔,所有也只有一個可以操作messageQueue的地方憎妙,保證一個線程只有一個messagQueue對象。
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
....
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;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
7.使用Message時應(yīng)該如何創(chuàng)建它曲楚?
為了保證內(nèi)存的復(fù)用厘唾,Message使用了享元設(shè)計(jì)模式,通過提供的obtain()函數(shù)來構(gòu)建Message對象龙誊,優(yōu)先使用已分配內(nèi)存并且清空數(shù)據(jù)的Message對象抚垃,如果不存在這樣的內(nèi)存對象,就new Message(只是個空函數(shù)) 構(gòu)建message 對象趟大,分配內(nèi)存鹤树。
在message對象被分配給handle之后,會調(diào)用 msg.recycleUnchecked();清空數(shù)據(jù)逊朽,復(fù)用內(nèi)存罕伯。
8.Looper死循環(huán)為什么不會導(dǎo)致應(yīng)用卡死。
anr是應(yīng)用無響應(yīng)叽讳,當(dāng)在主線程 執(zhí)行點(diǎn)擊操作 5s之內(nèi)沒有響應(yīng)追他, 或者廣播10s,服務(wù)20s岛蚤,執(zhí)行耗時操作沒有結(jié)束任務(wù)邑狸,就會報出ANR 應(yīng)用無響應(yīng) 彈窗。
無論是點(diǎn)擊事件涤妒,還是Anr事件都是一個message单雾,都需要Looper循環(huán)取出的。
比如 一個點(diǎn)擊事件届腐,生成一個message,在5s之內(nèi)沒有處理該message蜂奸,就會再發(fā)一個Anr message犁苏,因?yàn)樗膬?yōu)先級比較高,所以會先取出ANR的消息扩所,展示彈窗围详。
所以Looper的死循環(huán)和Anr不是一個層級的問題。
9.Handler 是怎么實(shí)現(xiàn)多線程通信的祖屏?
子線程中助赞,通過主線程創(chuàng)建的handler對象實(shí)例發(fā)送消息,調(diào)用messagQueue把消息加入消息隊(duì)列袁勺。messagQueue只是個容器雹食,沒有線程的區(qū)別。
因?yàn)橹骶€程創(chuàng)建的handler對象實(shí)例期丰,所以handler 對應(yīng)的looper就是ActivityThread main() 函數(shù)創(chuàng)建的looper群叶。
主線程中Looper.loop() 調(diào)用messagQueue.next() ,獲取對應(yīng)的message消息吃挑,通過handler.dispatchMessage() ,給回調(diào)函數(shù)handleMessage() 賦值街立。
子線程發(fā)送數(shù)據(jù)舶衬,主線程取出數(shù)據(jù),就這樣完成了線程之間的通信赎离。
Handler的擴(kuò)展使用
HandlerThread
HandlerThread 是Thread的子類,就是一個線程逛犹,只是在內(nèi)部幫助實(shí)現(xiàn)了Looper實(shí)例化。
方便使用梁剔,保證了線程安全虽画。
public class HandlerThread extends Thread {
.....
@Override
public void run() {
...
Looper.prepare();
synchronized (this) {//保證線程安全
mLooper = Looper.myLooper();
notifyAll();//激活所有等待的線程,進(jìn)入就緒狀態(tài)
}
....
Looper.loop();
.....
}
public Looper getLooper() {
.....
synchronized (this) { //保證線程安全憾朴,避免取出空looper
while (isAlive() && mLooper == null) {
try {
wait(); //進(jìn)入等待狀態(tài)
} catch (InterruptedException e) {
.....
}
}
}
......
return mLooper;
}
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) { //內(nèi)部創(chuàng)建Handler實(shí)例對象
mHandler = new Handler(getLooper());
}
return mHandler;
}
......
}
IntentService
是Service的子類狸捕,一般用于處理后臺耗時任務(wù)。內(nèi)部封裝 HandlerThread實(shí)現(xiàn)子線程處理耗時任務(wù)众雷。
內(nèi)部創(chuàng)建了Handler 實(shí)例對象灸拍,用來分發(fā)數(shù)據(jù)給回調(diào)函數(shù) onHandleIntent((Intent)msg.obj);
一個任務(wù)分成幾個子任務(wù),子任務(wù)按照順序先后執(zhí)行砾省,子任務(wù)全部執(zhí)行結(jié)束后鸡岗,這項(xiàng)任務(wù)才算成功。intentService就能完成這個任務(wù)编兄,并且很好的管理線程轩性,保證只有一個子線程處理工作,而且是一個一個完成任務(wù)狠鸳,有條不紊的順序執(zhí)行
@Deprecated
public abstract class IntentService extends Service {
....
//子線程 handler
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);//回調(diào)數(shù)據(jù)
stopSelf(msg.arg1);
}
}
....
@Override
public void onCreate() {
super.onCreate();
//構(gòu)建線程
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
//構(gòu)建子線程的handler
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
....
@Override
public void onDestroy() {
//退出循環(huán)
mServiceLooper.quit();
}
....
@WorkerThread //因?yàn)閔andler是子線程創(chuàng)建的揣苏,所以此函數(shù)也工作在子線程,可以執(zhí)行耗時操作
protected abstract void onHandleIntent(@Nullable Intent intent);
}