Handler機(jī)制分析

一、什么是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ī)制


Handler流程圖

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ì)象

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末芒篷,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子采缚,更是在濱河造成了極大的恐慌针炉,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扳抽,死亡現(xiàn)場(chǎng)離奇詭異篡帕,居然都是意外死亡殖侵,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門镰烧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)拢军,“玉大人,你說(shuō)我怎么就攤上這事怔鳖≤园Γ” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵结执,是天一觀的道長(zhǎng)度陆。 經(jīng)常有香客問(wèn)我,道長(zhǎng)献幔,這世上最難降的妖魔是什么懂傀? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮蜡感,結(jié)果婚禮上蹬蚁,老公的妹妹穿的比我還像新娘。我一直安慰自己郑兴,他們只是感情好犀斋,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著杈笔,像睡著了一般闪水。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蒙具,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天球榆,我揣著相機(jī)與錄音,去河邊找鬼禁筏。 笑死持钉,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的篱昔。 我是一名探鬼主播每强,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼州刽!你這毒婦竟也來(lái)了空执?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤穗椅,失蹤者是張志新(化名)和其女友劉穎辨绊,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體匹表,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡门坷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年宣鄙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片默蚌。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡冻晤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绸吸,到底是詐尸還是另有隱情鼻弧,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布惯裕,位于F島的核電站温数,受9級(jí)特大地震影響绣硝,放射性物質(zhì)發(fā)生泄漏蜻势。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一鹉胖、第九天 我趴在偏房一處隱蔽的房頂上張望握玛。 院中可真熱鬧,春花似錦甫菠、人聲如沸挠铲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)拂苹。三九已至,卻和暖如春痰洒,著一層夾襖步出監(jiān)牢的瞬間瓢棒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工丘喻, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留脯宿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓泉粉,卻偏偏與公主長(zhǎng)得像连霉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嗡靡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 旅行時(shí)跺撼,常有人在去景點(diǎn)的路上,邊步行邊問(wèn)還有幾分鐘到讨彼。其實(shí)不過(guò)兩三公里的路歉井,比平時(shí)鍛煉走一萬(wàn)步所需的公里數(shù)還短。但...
    黃慢糊閱讀 262評(píng)論 2 1
  • 如果我是一個(gè)巨人点骑,我知道 我的每一步都是生命在生長(zhǎng) 在夕陽(yáng)下我更應(yīng)該斟酌 腳下的大地是否是我的故鄉(xiāng) 這一把雙手揉皺...
    唐啵兒閱讀 153評(píng)論 2 2
  • 文 | 江水 看著小家伙兒在身前身后的活蹦亂跳酣难,不由得想起以前的一個(gè)驚險(xiǎn)事件谍夭,現(xiàn)在回想還會(huì)倒吸一口涼氣。 那是幾年...
    梨醒醒閱讀 322評(píng)論 0 0
  • 曲終人散 旁邊躺著的艾尼亞聽(tīng)到二人的對(duì)話摸不著頭緒憨募,嘗試著坐起來(lái)紧索,但身上的劇痛讓他用不上力氣“腹部被擊穿了,根本用...
    正反有李油閱讀 246評(píng)論 0 0
  • 工商管理學(xué)院16級(jí)新生中秋慰問(wèn)座談會(huì)順利召開 (冰花通訊社記者李心怡)9月13日14:40菜谣,工商管理學(xué)院16級(jí)新生...
    東北大學(xué)2018閱讀 283評(píng)論 0 0