1.為什么要用Handler
在Android中主線程又稱為UI線程蹂析,負(fù)責(zé)創(chuàng)建和更新UI糯钙,其他耗時(shí)操作如,訪問數(shù)據(jù)庫逞频,網(wǎng)絡(luò)請求纯衍,操作文件IO都需要放在子線程中執(zhí)行。
Android屏幕刷新大概是1秒60幀苗胀,每幀間隔16.67毫秒襟诸,為了保證刷新不掉幀,所以將耗時(shí)操作全部放在子線程中處理基协。
當(dāng)子線程處理完數(shù)據(jù)之后歌亲,為了防止UI處理邏輯的混亂,Android只允許主線程處理UI澜驮,這時(shí)候需要Handler來充當(dāng)子線程和主線程之間的橋梁陷揪。
為什么不加鎖:
1.鎖會讓UI邏輯混亂,無法保證執(zhí)行順序。
2.鎖會降低UI更新效率悍缠,會阻塞某些線程的執(zhí)行卦绣。
3.Android利用Handler隱示的添加了一把只能在主線程更新的鎖。因此Handler的消息處理機(jī)制是線程安全的
ps:在某些情況下可以在子線程更新UI飞蚓,例如onCreate 滤港,主線程更新完UI后馬上子線程再次更新UI ,或者在子線程更新固定寬高的控件玷坠。
2.Handler消息機(jī)制的原理
本質(zhì)就是Handler發(fā)送Message到MessageQueue中蜗搔,Looper遍歷消息分發(fā)給Hanlder處理。
Handler 主要涉及四個(gè)類
1.Message:消息
每個(gè)消息的攜帶者持有Handler八堡,存放在MessageQueue中樟凄,一個(gè)線程可以多個(gè)實(shí)例。
2.Hanlder:消息的發(fā)起者兄渺,處理者
發(fā)送Message及處理回調(diào)事件缝龄,一個(gè)線程可以存在多個(gè)實(shí)例。
3.Looper:消息的遍歷者
從MessageQueue中遍歷出每個(gè)Message進(jìn)行處理挂谍,一個(gè)線程一個(gè)實(shí)例叔壤。
4.MessageQueue:消息隊(duì)列
存放Handler發(fā)送的消息,提供給Looper遍歷口叙,一個(gè)線程一個(gè)炼绘。
Looper.prepare()
方法中在ThreadLocal中獲取一個(gè)Looper。
因此確保每個(gè)線程中只有一個(gè)Looper妄田。
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
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));
}
3.Looper的啟動(dòng)
ActivityThread作為程序的第一個(gè)入口俺亮,main方法中調(diào)用Looper.prepareMainLooper創(chuàng)建了一個(gè)Looper。
并調(diào)用Looper.loop();方法
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
4.Looper的循環(huán)
public static void loop() {
//獲取當(dāng)前線程的Looper對象
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//獲取對應(yīng)的消息隊(duì)列
final MessageQueue queue = me.mQueue;
...
//死循環(huán)
for (;;) {
//在消息隊(duì)列中獲取消息
Message msg = queue.next(); // might block
if (msg == null) {
return;
}
...
try {
//target 是 Message 中保存處理消息的Handler實(shí)例疟呐。
msg.target.dispatchMessage(msg);
} catch (Exception exception) {
throw exception;
}
...
msg.recycleUnchecked();
}
}
5.MessageQueue的next();
如果沒有消息可以回去會執(zhí)行nativePollOnce方法陷入沉睡, 等待喚醒脚曾。
添加消息到隊(duì)列中enqueueMessage方法會進(jìn)行調(diào)用nativeWake方法喚醒。
6.nativePollOnce 和 nativeWake
目前還無法看懂具體實(shí)現(xiàn)启具。后續(xù)看明白會補(bǔ)上本讥。
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
private native static void nativeWake(long ptr);