Handler
Android整個(gè)ui體系都是圍繞handler的消息機(jī)制,handler可以在子線程發(fā)送消息,在主線程接收處理消息,從而實(shí)現(xiàn)線程的跨越,所有有必要對(duì)其進(jìn)行更加深入的掌握
從一般的使用上看,handler的使用分為發(fā)送消息和接收消息
//實(shí)例化一個(gè)handler對(duì)象
val mHandler = Handler(Looper.getMainLooper()){
//do some thing in main thread
false
}
//通過(guò)handler對(duì)象發(fā)送消息
mHandler.sendEmptyMessage(-1)
消息的發(fā)送
使用還是很熟悉的,發(fā)送端發(fā)送消息,除了發(fā)送空的消息,還可以傳遞一個(gè)帶參數(shù)的Messge對(duì)象,還有延時(shí)發(fā)送消息的api方法

具體的看一下其中的調(diào)用流程

這里有一些需要注意的點(diǎn)
Message的實(shí)例化是通過(guò)Message.obtain()方法,而不是直接new Message()
Message對(duì)象會(huì)持有發(fā)送者Handler的引用,并賦值在msg.target 屬性上
在msg入隊(duì)之前,會(huì)判斷mAsynchronous屬性的值,并將msg對(duì)應(yīng)的值進(jìn)行賦值
通過(guò)Handler的send操作,就會(huì)產(chǎn)生一個(gè)附帶有額外信息的Message對(duì)象和相應(yīng)的延遲時(shí)間屬性,那么看看mQueue這個(gè)隊(duì)列是從哪來(lái)的
Handler中的Looper
//Handler
public class Handler {
//mQueue是Handler的一個(gè)成員屬性
final MessageQueue mQueue;
final Looper mLooper;
public Handler(@Nullable Callback callback, boolean async) {
//...省略
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
}
Handler中的mQueue和mLooper屬性都是在Handler()構(gòu)造函數(shù)中進(jìn)行賦值引用的,可以看出handler中持有的MessageQueue是從對(duì)應(yīng)的Looper中拿到的,那看一下Looper這個(gè)類
public final class Looper {
//ThreadLocal的常量
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
private Printer mLogging;
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
//Looper的創(chuàng)建
public static void prepare() {
prepare(true);
}
//從ThreadLocal中去獲取對(duì)應(yīng)的Looper,這個(gè)方法只能調(diào)用一次,如果重復(fù)調(diào)用,會(huì)拋出異常
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//會(huì)直接通過(guò)new Looper()的方式創(chuàng)建一個(gè)Looper,并調(diào)用ThreadLocal$set進(jìn)行保存
sThreadLocal.set(new Looper(quitAllowed));
}
}
//Looper初始化后調(diào)用的保存方式
public class ThreadLocal<T> {
public T get() {
//獲取當(dāng)前線程
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
public void set(T value) {
//獲取當(dāng)前線程
Thread t = Thread.currentThread();
//從下面可以Thread類可以看出,每一個(gè)線程會(huì)有一個(gè)ThreadLocalMap的成員屬性
ThreadLocalMap map = getMap(t);
if (map != null)
//Map其實(shí)就是一個(gè)hashmap,里面會(huì)有一個(gè)Entry數(shù)組,Entry保存了一個(gè)鍵值對(duì),而key的類型就是ThreadLocal
map.set(this, value);
else
createMap(t, value);
}
//獲取對(duì)應(yīng)線程的ThreadLocalMap
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
}
public class Thread implements Runnable {
ThreadLocal.ThreadLocalMap threadLocals = null;
}
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
private Entry[] table;
private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;
//...省略
tab[i] = new Entry(key, value);
}
}
小結(jié)一下:Looper的初始化和線程唯一
-
Handler構(gòu)造函數(shù)初始化,傳入了Looper參數(shù)就直接賦值,沒(méi)有傳入就通過(guò)Looper.myLooper()獲取
構(gòu)造函數(shù)讓Handler的mLooper對(duì)象有值,并且將其中的MessageQueue進(jìn)行傳遞
-
Looper.myLooper()的函數(shù)->調(diào)用其內(nèi)部的 sThreadLocal.get()
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
sThreadLocal是一個(gè)常量,所以得看其內(nèi)部具體的get()邏輯
-
ThreadLocal的set()/get()方法都是先獲取當(dāng)前的線程#Thread.currentThread()#,然后獲取線程內(nèi)部的ThreadLocalMap對(duì)象,這個(gè)Map對(duì)象的key就是ThreadLocal的一個(gè)弱引用
Looper初始化的時(shí)候,調(diào)用#prepare()方法,會(huì)通過(guò)new Looper()的方法直接實(shí)例化一個(gè)Looper對(duì)象,通過(guò)ThreadLocal的set方法,會(huì)將這個(gè)Looper對(duì)象設(shè)置到對(duì)應(yīng)線程的ThreadLocalMap屬性中,這個(gè)屬性其實(shí)是一個(gè)HashMap,對(duì)應(yīng)的key就是Looper中的常量ThreadLocal,所以線程通過(guò)這個(gè)key會(huì)找到唯一對(duì)應(yīng)的Looper值
不同的線程對(duì)應(yīng)的ThreadLocalMap是不同的對(duì)象,雖然都是looper中的常量ThreadLocal作為key,但是容器不一樣,所以Looper是線程唯一的
線程內(nèi)的Handler可以直接sendmessage()嗎
//在線程里面調(diào)用一個(gè)不傳Looper參數(shù)的Handler構(gòu)造方法
//調(diào)用Looper.myLooper()->sThreadLocal.get() 由于該線程沒(méi)有初始化設(shè)置Looper對(duì)象,所以這樣寫(xiě)會(huì)崩潰
new Thread(new Runnable() {
@Override
public void run() {
//線程里面
// Looper.prepare();
// Looper.loop();
Handler mHandler = new Handler(msg -> {
return false;
}
);
mHandler.sendEmptyMessage(-1);
}
}).start();
//錯(cuò)誤信息,線程沒(méi)有調(diào)用Looper.prepare(),所以找不到對(duì)應(yīng)的looper對(duì)象
java.lang.RuntimeException: Can't create handler inside thread Thread[Thread-2,5,main] that has not called Looper.prepare()
通過(guò)上面的流程,對(duì)Handlder和Looper的關(guān)系有一個(gè)理解了
Handler中有一個(gè)Looper的成員屬性,默認(rèn)情況下,這個(gè)Looper對(duì)象是handler所屬當(dāng)前線程的唯一值
主線程中的Looper
public final class ActivityThread extends ClientTransactionHandler {
public static void main(String[] args) {
//...省略各種不相關(guān)的代碼
Looper.prepareMainLooper();
Looper.loop();
}
}
->Looper.java
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
app進(jìn)程的main()函數(shù)在ActivityThread類中,從里面可以看出,最終也是調(diào)用了Looper$prepare()方法,對(duì)我們熟悉的主線程進(jìn)行Looper的初始化
Looper中的MessageQueue
public final class Looper {
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
}
從上文可以看到,Looper.prepare()方法中,會(huì)直接new一個(gè)Looper對(duì)象,而Looper的構(gòu)造函數(shù)中,也是直接new了一個(gè)MessageQueue對(duì)象
queue.enqueueMessage
最前面的handler發(fā)送邏輯,最后msg對(duì)象和延遲時(shí)間都是通過(guò)queue.enqueueMessage()進(jìn)行操作的,現(xiàn)在就分析一下怎么入隊(duì)的
public final class MessageQueue {
private final boolean mQuitAllowed;
Message mMessages;
boolean enqueueMessage(Message msg, long when) {
//target就是handler的引用
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
//子線程可以使用主線程的handler進(jìn)行發(fā)送消息,入隊(duì)的操作需要同步鎖
synchronized (this) {
//退出循環(huán)了,后續(xù)入隊(duì)的直接拋異常
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
//消息的回收復(fù)用方法
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
//消息是個(gè)鏈表,先取出頭節(jié)點(diǎn)
//判斷插入鏈表頭部的情況,空隊(duì)列,不需要等待的消息來(lái)了,如果當(dāng)前插入的消息在頭消息更早的時(shí)間
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;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
}
//結(jié)合Message的數(shù)據(jù)結(jié)構(gòu)
public final class Message implements Parcelable {
//鏈表的下一個(gè)節(jié)點(diǎn)的引用
Message next;
//用來(lái)回收復(fù)用加鎖
public static final Object sPoolSync = new Object();
//對(duì)象池也是使用的鏈表
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
//取頭節(jié)點(diǎn)進(jìn)行復(fù)用
Message m = sPool;
//對(duì)象池頭節(jié)點(diǎn)后移一位
sPool = m.next;
//清理復(fù)用對(duì)象的引用關(guān)系
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
//回收池里面沒(méi)有可復(fù)用的對(duì)象,直接new
return new Message();
}
//回收消息對(duì)象
void recycleUnchecked() {
//清洗對(duì)象的屬性值
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;
//因?yàn)橛墟湵淼氖孜碴P(guān)系,需要加鎖
synchronized (sPoolSync) {
//最大回收池大小是50個(gè)
if (sPoolSize < MAX_POOL_SIZE) {
//回收的對(duì)象是插在頭部的,將回收對(duì)象的next指針指向當(dāng)前的頭節(jié)點(diǎn)
next = sPool;
//頭節(jié)點(diǎn)又引用當(dāng)前回收的對(duì)象
sPool = this;
sPoolSize++;
}
}
}
}
Message入隊(duì)過(guò)程
Message使用了鏈表的數(shù)據(jù)結(jié)構(gòu),通過(guò)next屬性指向下一個(gè)Message對(duì)象
Message中有個(gè)sPool的回收池,回收池就是Message的鏈表隊(duì)列
通過(guò)obtain()方法會(huì)從回收池中去取頭節(jié)點(diǎn),存在會(huì)將回收池后移,如果不存在直接new出一個(gè)對(duì)象
通過(guò)recycleUnchecked()回收Message,也是清空屬性后插入到頭節(jié)點(diǎn)
-
MessageQueue就是一個(gè)Message的鏈表,入隊(duì)的時(shí)候,通過(guò)判斷Message的延遲時(shí)間,進(jìn)行排序插入
通過(guò)上面分析,handler發(fā)送消息入隊(duì)的操作,最終會(huì)得到一個(gè)按延遲時(shí)間排序的有序鏈表,發(fā)送端基本就分析完了,接下來(lái)看一看消息的消費(fèi)
消息的消費(fèi)
上面注意到的點(diǎn),在Looper.prepare()初始化了Looper對(duì)象后,然后不斷的往Looper中的messageQueue發(fā)送消息,代碼層面對(duì)Looper的操作就只有 Looper.loop()方法,所以消息的消費(fèi)就在這里面
###Looper.java
public static void loop() {
//獲取當(dāng)前線程的looper
final Looper me = myLooper();
//取出對(duì)應(yīng)的MessageQueue
final MessageQueue queue = me.mQueue;
//消息消費(fèi)的關(guān)鍵代碼,通過(guò)一個(gè)死循環(huán)進(jìn)行輪詢?nèi)∠? for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//Looper中如果設(shè)置Printer對(duì)象,消息的消費(fèi)過(guò)程會(huì)輸出日志
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
//...省略
try {
//取出發(fā)送消息的handler,回調(diào)到我們的界面的地方
msg.target.dispatchMessage(msg);
} catch (Exception exception) {
//...
} finally {
//...
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
//消息回收復(fù)用
msg.recycleUnchecked();
}
}
Message的消費(fèi)還是比較簡(jiǎn)單,通過(guò)Looper的死循環(huán),不斷的從消息隊(duì)列中去取消息,然后將對(duì)應(yīng)的消息分發(fā)出去,就能回調(diào)到我們熟悉的dispatchMessage()方法中了,最后將消息進(jìn)行回收復(fù)用
值得注意的點(diǎn)
- Looper對(duì)象中如果設(shè)置了Printer屬性,在消息分發(fā)的過(guò)程中,開(kāi)始處理和處理結(jié)束都會(huì)打印日志輸出
public interface Printer {
/**
* Write a line of text to the output. There is no need to terminate
* the given string with a newline.
*/
void println(String x);
}
Printer是一個(gè)接口,這個(gè)點(diǎn)可以用來(lái)做簡(jiǎn)單的頁(yè)面FPS監(jiān)控,頁(yè)面的刷新最終也是通過(guò)handler機(jī)制發(fā)送的一個(gè)發(fā)送一個(gè)message進(jìn)行刷新繪制
總結(jié)
終于從前到后從源碼中找到關(guān)鍵代碼,梳理了一遍常用的消息機(jī)制handler的發(fā)送和消費(fèi)過(guò)程,其中涉及到相關(guān)的Looper和Message對(duì)象,記錄了Looper的線程唯一性的原因
一些有所了解還沒(méi)整理總結(jié)的點(diǎn)
- 對(duì)于looper死循環(huán)的退出(exit())和主線程死循環(huán)沒(méi)有ANR相關(guān)的epoll機(jī)制暫時(shí)沒(méi)有分析,epoll的底層原理理解起來(lái)有點(diǎn)麻煩,通俗一點(diǎn)就是messagequeue隊(duì)列里面沒(méi)有message需要處理的時(shí)候,會(huì)通過(guò)epoll機(jī)制進(jìn)行休眠,然后在需要處理的時(shí)候wake喚醒進(jìn)行消息處理
- message的target==null的情況下,消息屏障處理異步消息的流程沒(méi)有分析
handler這個(gè)貫穿整個(gè)app的生命周期,也經(jīng)常在群里看到討論Message的復(fù)用機(jī)制,MessageQueue的設(shè)計(jì),Looper的線程唯一性,MessageQueue的池子大小等問(wèn)題,還是得梳理源碼,一下就清晰了,如果有理解錯(cuò)誤的地方,歡迎指導(dǎo)