一、什么是handler埠帕?
handler是Android給我們提供用來(lái)更新UI的一套機(jī)制垢揩,也是一套消息處理機(jī)制,我們可以發(fā)消息敛瓷,也可以通過(guò)它 處理消息叁巨。
二、那為什么要用handler呢?我能不能不用呐籽?
肯定是不行的锋勺。因?yàn)閍ndroid在設(shè)計(jì)的時(shí)候就封裝了一套消息創(chuàng)建、傳遞狡蝶、處理庶橱。如果不遵循就不能更新UI信息,就會(huì)報(bào)出異常贪惹。
三苏章、Android為什么要設(shè)計(jì)只能用handler機(jī)制更新UI呢?
最根本的目的就是為了解決多線程并發(fā)的問(wèn)題奏瞬!
? ? ? ? ? ?打個(gè)比方枫绅,如果在一個(gè)activity中有多個(gè)線程,并且沒(méi)有加鎖丝格,就會(huì)出現(xiàn)界面錯(cuò)亂的問(wèn)題撑瞧。但是如果對(duì)這些更新UI的操作都加鎖處理棵譬,又會(huì)導(dǎo)致性能下降显蝌。
? ? ? ? ? 處于對(duì)性能的問(wèn)題考慮,Android給我們提供這一套更新UI的機(jī)制我們只需要遵循這種機(jī)制就行了。不用再去關(guān)系多線程的問(wèn)題曼尊,所有的更新UI的操作酬诀,都是在主線程的消息隊(duì)列中去輪訓(xùn)的。
四骆撇、handler中send和post方法的區(qū)別
在Android中handler用來(lái)進(jìn)行進(jìn)程間通信瞒御,其中有send和post兩種方法,大家常用的send方法神郊,其是在工作線程中處理完耗時(shí)操作后調(diào)用handler的sendMessage(message)把message對(duì)象發(fā)送給主線程肴裙,在主線程中重寫handlerMessage()方法,判斷接收到的消息進(jìn)行更新UI的操作涌乳;而post方法傳遞的是一個(gè)runnable對(duì)象蜻懦,更新UI的操作也是在這個(gè)runnable的run方法中進(jìn)行的,也就是說(shuō)run方法中的代碼是執(zhí)行在主線程中的夕晓,雖然它是寫在工作線程中宛乃,主線程在接收到消息后自動(dòng)執(zhí)行runnable的run方法中的代碼。
public class MainActivity extends Activity {
??? private Button btSend;
??? private Button btPost;
??? private TextView textview;
??? private static final int SEND_UPDATA_TEXT=0;
??? private Handler handler=new Handler(){
?? ??? ?public void handleMessage(Message msg) {
?? ??? ??? ?switch (msg.what) {
?? ??? ??? ?case SEND_UPDATA_TEXT:
?? ??? ??? ??? ?textview.setText("sendMessage發(fā)來(lái)的消息");
?? ??? ??? ??? ?break;
?? ??? ??? ?default:
?? ??? ??? ??? ?break;
?? ??? ??? ?}
?? ??? ?};
??? };
?? ?@Override
?? ?protected void onCreate(Bundle savedInstanceState) {
?? ??? ?super.onCreate(savedInstanceState);
?? ??? ?setContentView(R.layout.activity_main);
?? ??? ?//初始化控件
?? ??? ?setViews();
?? ??? ?//事件監(jiān)聽(tīng)
?? ??? ?setListener();
?? ?}
?? ?private void setListener() {
?? ??? btSend.setOnClickListener(new OnClickListener() {
?? ??? ?@Override
?? ??? ?public void onClick(View v) {
?? ??? ??? ?new Thread(new Runnable() {
?? ??? ??? ??? ?@Override
?? ??? ??? ??? ?public void run() {
?? ??? ??? ??? ??? ?Message message=new Message();
?? ??? ??? ??? ??? ?message.what=SEND_UPDATA_TEXT;
?? ??? ??? ??? ??? ?handler.sendMessage(message);
?? ??? ??? ??? ?}
?? ??? ??? ?}).start();
?? ??? ?}
?? ?});
?? ??? btPost.setOnClickListener(new OnClickListener() {
?? ??? ?@Override
?? ??? ?public void onClick(View v) {
?? ??? ??? ?new Thread(new Runnable() {
?? ??? ??? ??? ?@Override
?? ??? ??? ??? ?public void run() {
?? ??? ??? ??? ??? ?//使用post發(fā)送消息
?? ??? ??? ??? ??? ?handler.post(new Runnable() {
?? ??? ??? ??? ??? ??? ?//run方法中的代碼執(zhí)行在UI線程中
?? ??? ??? ??? ??? ??? ?@Override
?? ??? ??? ??? ??? ??? ?public void run() {
?? ??? ??? ??? ??? ??? ??? ?textview.setText("post發(fā)來(lái)消息");
?? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?});
?? ??? ??? ??? ?}
?? ??? ??? ?}).start();
?? ??? ?}
?? ?});
?? ?}
?? ?private void setViews() {
?? ??? ?btSend=(Button) findViewById(R.id.bt_send);
?? ??? ?btPost=(Button) findViewById(R.id.bt_post);
?? ??? ?textview=(TextView) findViewById(R.id.textview);
?? ?}
}
源碼流程分析
handler 發(fā)送Message(消息)至MessageQueue(模擬隊(duì)列)蒸辆,由Looper(循環(huán)器)不斷的循環(huán)取出征炼,然后通知handler處理消息,這是整個(gè)消息機(jī)制
Looper 消息輪訓(xùn)器
MessageQueue消息暫存隊(duì)列(單鏈表結(jié)構(gòu))
Message 消息
Handler 收發(fā)消息工具
請(qǐng)解釋下在單線程模型中Message躬贡、Handler谆奥、Message Queue、Looper之間的關(guān)系拂玻。
答:簡(jiǎn)單的說(shuō)雄右,Handler獲取當(dāng)前線程中的looper對(duì)象,looper用來(lái)從存放Message的MessageQueue中取出Message纺讲,再有Handler進(jìn)行Message的分發(fā)和處理.
Message Queue(消息隊(duì)列)/8:用來(lái)存放通過(guò)Handler發(fā)布的消息擂仍,通常附屬于某一個(gè)創(chuàng)建它的線程,可以通過(guò)Looper.myQueue()得到當(dāng)前線程的消息隊(duì)列
Handler:可以發(fā)布或者處理一個(gè)消息或者操作一個(gè)Runnable熬甚,通過(guò)Handler發(fā)布消息逢渔,消息將只會(huì)發(fā)送到與它關(guān)聯(lián)的消息隊(duì)列,然也只能處理該消息隊(duì)列中的消息
Looper:是Handler和消息隊(duì)列之間通訊橋梁乡括,程序組件首先通過(guò)Handler把消息傳遞給Looper肃廓,Looper把消息放入隊(duì)列。Looper也把消息隊(duì)列里的消息廣播給所有的
Handler:Handler接受到消息后調(diào)用handleMessage進(jìn)行處理
Message:消息的類型诲泌,在Handler類中的handleMessage方法中得到單個(gè)的消息進(jìn)行處理
在單線程模型下盲赊,為了線程通信問(wèn)題,Android設(shè)計(jì)了一個(gè)Message Queue(消息隊(duì)列)敷扫, 線程間可以通過(guò)該Message Queue并結(jié)合Handler和Looper組件進(jìn)行信息交換哀蘑。下面將對(duì)它們進(jìn)行分別介紹:
1)?Message
?Message消息,理解為線程間交流的信息,處理數(shù)據(jù)后臺(tái)線程需要更新UI绘迁,則發(fā)送Message內(nèi)含一些數(shù)據(jù)給UI線程合溺。
2)?Handler
?Handler處理者,是Message的主要處理者缀台,負(fù)責(zé)Message的發(fā)送棠赛,Message內(nèi)容的執(zhí)行處理。后臺(tái)線程就是通過(guò)傳進(jìn)來(lái)的 Handler對(duì)象引用來(lái)sendMessage(Message)膛腐。而使用Handler睛约,需要implement 該類的 handleMessage(Message)方法,它是處理這些Message的操作內(nèi)容哲身,例如Update UI痰腮。通常需要子類化Handler來(lái)實(shí)現(xiàn)handleMessage方法。
3)?Message Queue
?Message Queue消息隊(duì)列律罢,用來(lái)存放通過(guò)Handler發(fā)布的消息膀值,按照先進(jìn)先出執(zhí)行。
?每個(gè)message queue都會(huì)有一個(gè)對(duì)應(yīng)的Handler误辑。Handler會(huì)向message queue通過(guò)兩種方法發(fā)送消息:sendMessage或post沧踏。這兩種消息都會(huì)插在message queue隊(duì)尾并按先進(jìn)先出執(zhí)行。但通過(guò)這兩種方法發(fā)送的消息執(zhí)行的方式略有不同:通過(guò)sendMessage發(fā)送的是一個(gè)message對(duì)象,會(huì)被 Handler的handleMessage()函數(shù)處理巾钉;而通過(guò)post方法發(fā)送的是一個(gè)runnable對(duì)象翘狱,則會(huì)自己執(zhí)行。
4)?Looper
?Looper是每條線程里的Message Queue的管家砰苍。Android沒(méi)有Global的Message Queue潦匈,而Android會(huì)自動(dòng)替主線程(UI線程)建立Message Queue,但在子線程里并沒(méi)有建立Message Queue赚导。所以調(diào)用Looper.getMainLooper()得到的主線程的Looper不為NULL茬缩,但調(diào)用Looper.myLooper() 得到當(dāng)前線程的Looper就有可能為NULL。對(duì)于子線程使用Looper吼旧,API Doc提供了正確的使用方法:這個(gè)Message機(jī)制的大概流程:
?①在Looper.loop()方法運(yùn)行開始后凰锡,循環(huán)地按照接收順序取出Message Queue里面的非NULL的Message。
② 一開始Message Queue里面的Message都是NULL的圈暗。當(dāng)Handler.sendMessage(Message)到Message Queue掂为,該函數(shù)里面設(shè)置了那個(gè)Message對(duì)象的target屬性是當(dāng)前的Handler對(duì)象。隨后Looper取出了那個(gè)Message员串,則調(diào)用 該Message的target指向的Hander的dispatchMessage函數(shù)對(duì)Message進(jìn)行處理勇哗。在dispatchMessage方法里,如何處理Message則由用戶指定寸齐,三個(gè)判斷欲诺,優(yōu)先級(jí)從高到低:
a)?Message里面的Callback抄谐,一個(gè)實(shí)現(xiàn)了Runnable接口的對(duì)象,其中run函數(shù)做處理工作瞧栗;
b)?Handler里面的mCallback指向的一個(gè)實(shí)現(xiàn)了Callback接口的對(duì)象斯稳,由其handleMessage進(jìn)行處理海铆;
c)?處理消息Handler對(duì)象對(duì)應(yīng)的類繼承并實(shí)現(xiàn)了其中handleMessage函數(shù)迹恐,通過(guò)這個(gè)實(shí)現(xiàn)的handleMessage函數(shù)處理消息。
?由此可見(jiàn)卧斟,我們實(shí)現(xiàn)的handleMessage方法是優(yōu)先級(jí)最低的殴边!
?③ Handler處理完該Message (update UI) 后,Looper則設(shè)置該Message為NULL珍语,以便回收锤岸!
?在網(wǎng)上有很多文章講述主線程和其他子線程如何交互,傳送信息板乙,最終誰(shuí)來(lái)執(zhí)行處理信息之類的是偷,個(gè)人理解是最簡(jiǎn)單的方法——判斷Handler對(duì)象里面的Looper對(duì)象是屬于哪條線程的,則由該線程來(lái)執(zhí)行募逞!
①當(dāng)Handler對(duì)象的構(gòu)造函數(shù)的參數(shù)為空蛋铆,則為當(dāng)前所在線程的Looper;
②Looper.getMainLooper()得到的是主線程的Looper對(duì)象放接,Looper.myLooper()得到的是當(dāng)前線程的Looper對(duì)象刺啦。
來(lái)講講一下handler機(jī)制
一個(gè)允許你發(fā)送和處理Message和Runable對(duì)象,每個(gè)線程都有自己的Looper纠脾,每個(gè)Looper中封裝著MessageQueue玛瘸。Looper負(fù)責(zé)不斷的從自己的消息隊(duì)列里取出隊(duì)頭的任務(wù)或消息執(zhí)行。每個(gè)handler也和線程關(guān)聯(lián)苟蹈,Handler負(fù)責(zé)把Message和Runable
對(duì)象傳遞給MessageQueue(用到post糊渊,sendMessage等方法),而且在這些對(duì)象離開MessageQueue時(shí)慧脱,Handler負(fù)責(zé)執(zhí)行他們(用到handleMessage方法)再来。
其中Message類就是定義了一個(gè)信息,這個(gè)信息中包含一個(gè)描述符和任意的數(shù)據(jù)對(duì)象磷瘤,這個(gè)信息被用來(lái)傳遞給Handler.Message對(duì)象