handler是用looper輪詢消息的。
那么我們此次分析的重點就是分析Looper.loop方法翠勉。
首先從looper的loop方法開始
因為loop要不斷地接受消息。
此時有兩種方案
1.一種是死循環(huán)不停的去判斷有沒有消息
2.通過wait/notify方法螟碎,讓線程阻塞眉菱,當(dāng)子線程發(fā)出消息時,調(diào)用notify方法通知主線程接收消息
顯示掉分,第二種方案效率高得多俭缓,looper又是一個常用功能克伊,所以必須做出一個極限的效率優(yōu)化。
早在Android2.2的時代华坦,loop方法用的是java里object類里的wait方法等待消息的愿吹。這里不詳細(xì)介紹。
在Android2.3以后(目前Android推出8.0)惜姐,loop的核心實現(xiàn)都用jni藏在c++里犁跪,那么接下來我們詳細(xì)的分析一下c++層
1.首先java層的Looper.loop方法里有一個for(;歹袁;)坷衍,循環(huán)執(zhí)行MessageQueue的next()方法取到消息
2.MessageQueue類的next方法通過調(diào)用nativePollOnce方法獲取msg
3.android_os_MessageQueue_nativePollOnce方法通過調(diào)用了pollOnce方法,我們繼續(xù)跟蹤調(diào)用棧
4.pollOnce調(diào)用了mLooper的pollOnce方法条舔,我們在跟進(jìn)枫耳。
5.pollOnce調(diào)用pollInner方法
6.pollInner方法里面調(diào)用了epoll_wait方法,這個方法跟java的wait方法的功能類似孟抗,都是讓線程阻塞迁杨。
到這里我們終于看到了裸漏在外的epoll,
那么epoll是什么呢凄硼?
epoll實現(xiàn)了線程阻塞铅协,跟java的wait方法的功能相似。
因為epoll擁有優(yōu)秀的效率摊沉,乃至成為一種輪詢時的標(biāo)準(zhǔn)狐史,所以在著名的輪詢使用場景中都有epoll方法的身影。
比如包括nginx在內(nèi)的大多數(shù)服務(wù)器輪詢接受客戶端的請求说墨。
我模仿Looper寫了一個最簡單的epoll使用方式预皇,獻(xiàn)上代碼,https://github.com/ChinaTengFei/easyLooper
代碼很簡單婉刀,創(chuàng)建了幾個子線程一個主線程,子線程通過epoll跟主線程進(jìn)行通訊序仙。
那么此時我們知道了jni層是如何實現(xiàn)線程的阻塞突颊,我們也知道了輪詢的原理。接下來分析下子線程發(fā)消息的代碼
從Handler.java的sendMessageAtTime開始分析潘悼,
~ sendMessageAtTime方法間接調(diào)用了MessageQueueen的queueMessage方法
~ 在queueMessage方法中最后有一個if判斷律秃,if(needWake)
~ needWake=需要喚醒
~ 正常情況下needWake為true,那么就調(diào)用nativeWake方法喚醒主線程
下面是c++層
~ nativeWake調(diào)用了NativeMessageQueue類的wake方法
~ wake方法調(diào)用了Looper的wake方法:mLooper->wake();
~ wake方法調(diào)用write方法寫入數(shù)據(jù)治唤。
~ 此時epoll監(jiān)聽到有數(shù)據(jù)寫入棒动。就把數(shù)據(jù)返回到j(luò)ava層。
同樣寫入數(shù)據(jù)也可以參考我的這個小demo宾添,https://github.com/ChinaTengFei/easyLooper