簡單聊聊Handler機制

想要了解handler機制那么我們先要知道它的作用,大家都知道在android中,UI線程是非線程安全的觅赊,也就是更新UI只能在UI線程中完成,其他工作線程無法直接操作UI線程琼稻。耗時操作要在工作線程中完成(不能阻塞主線程)吮螺。為了解決以上問題,Android設(shè)計了Handler機制帕翻,由Handler來負責(zé)與子線程進行通訊鸠补,從而讓子線程與主線程之間建立起協(xié)作的橋梁。

相信看完上面的話大家對handler有了個大概的了解嘀掸,我們再來看看Handler 紫岩、 Looper 、Message 這三者與Android異步消息處理線程相關(guān)的概念睬塌。那么什么叫異步消息處理線程呢泉蝌?

異步消息處理線程啟動后會進入一個無限的循環(huán)體之中,每循環(huán)一次揩晴,從其內(nèi)部的消息隊列中取出一個消息勋陪,然后回調(diào)相應(yīng)的消息處理函數(shù),執(zhí)行完成一個消息后則繼續(xù)循環(huán)硫兰。若消息隊列為空诅愚,線程則會阻塞等待。

說了這一堆劫映,那么和Handler 违孝、 Looper 、Message有啥關(guān)系泳赋?其實Looper負責(zé)的就是創(chuàng)建一個MessageQueue雌桑,然后進入一個無限循環(huán)體不斷從該MessageQueue中讀取消息,而消息的創(chuàng)建者就是一個或多個Handler 摹蘑。

我們首先看一下looper的prepare()方法筹燕。

prepare()方法

public static final void prepare() {

if(sThreadLocal.get()?!=null)?{

thrownewRuntimeException("Only?one?Looper?may?be?created?per?thread");

}

sThreadLocal.set(newLooper(true));

}

從代碼中我們可以看出 將一個looper的對象放入到sThreadLocal當(dāng)中,并且sThreadLocal如果不為空就拋出異常,那么說明prepare()被重復(fù)調(diào)用就會拋出異常撒踪,那么也就是一個線程中只有一個looper實例过咬。

我們再來看一下looper的構(gòu)造方法

private Looper(boolean quitAllowed) {

mQueue?=new MessageQueue(quitAllowed);

mRun?=true;

mThread?=?Thread.currentThread();

}

我們可以看到構(gòu)造looper 被初始化的同時也會初始化一個MessageQueue(消息隊列)

我們再來看一下loop()方法

public static void loop() {

finalLooper?me?=?myLooper();

if(me?==null)?{

throw new RuntimeException("No?Looper;?Looper.prepare()?wasn't?called?on?this?thread.");

}

final MessageQueue?queue?=?me.mQueue;

//?Make?sure?the?identity?of?this?thread?is?that?of?the?local?process,

//?and?keep?track?of?what?that?identity?token?actually?is.

Binder.clearCallingIdentity();

final longident?=?Binder.clearCallingIdentity();

for(;;)?{

Message?msg?=?queue.next();//?might?block

if(msg?==null)?{

//?No?message?indicates?that?the?message?queue?is?quitting.

return;

}

//?This?must?be?in?a?local?variable,?in?case?a?UI?event?sets?the?logger

Printer?logging?=?me.mLogging;

if(logging?!=null)?{

logging.println(">>>>>?Dispatching?to?"+?msg.target?+"?"+

msg.callback?+":?"+?msg.what);

}

msg.target.dispatchMessage(msg);

if(logging?!=null)?{

logging.println("<<<<<?Finished?to?"+?msg.target?+"?"+?msg.callback);

}

//?Make?sure?that?during?the?course?of?dispatching?the

//?identity?of?the?thread?wasn't?corrupted.

final longnewIdent?=?Binder.clearCallingIdentity();

if(ident?!=?newIdent)?{

Log.wtf(TAG,"Thread?identity?changed?from?0x"

+?Long.toHexString(ident)?+"?to?0x"

+?Long.toHexString(newIdent)?+"?while?dispatching?to?"

+?msg.target.getClass().getName()?+"?"

+?msg.callback?+"?what="+?msg.what);

}

msg.recycle();

}

}




myLooper()這個方法返回的Looper實例,如果me為null則拋出異常制妄,也就是說looper方法必須在prepare方法之后運行掸绞。

me.mQueue拿到該looper實例中的mQueue(消息隊列),在for循環(huán) 這個方法Message msg = queue.next();里取出一條消息耕捞,如果沒有消息則阻塞衔掸。

調(diào)用? msg.target.dispatchMessage(msg);把消息交給msg的target的dispatchMessage方法去處理消息,target其實就是Handler實例

looper介紹完了俺抽,我們再來看看Handler


public? Handler() {

this(null,false);

}

public Handler(Callback?callback,booleanasync)?{

if(FIND_POTENTIAL_LEAKS)?{

finalClass?klass?=?getClass();

if((klass.isAnonymousClass()?||?klass.isMemberClass()?||?klass.isLocalClass())?&&

(klass.getModifiers()?&?Modifier.STATIC)?==0)?{

Log.w(TAG,"The?following?Handler?class?should?be?static?or?leaks?might?occur:?"+

klass.getCanonicalName());

}

}

mLooper?=?Looper.myLooper();

if(mLooper?==null)?{

thrownewRuntimeException(

"Can't?create?handler?inside?thread?that?has?not?called?Looper.prepare()");

}

mQueue?=?mLooper.mQueue;

mCallback?=?callback;

mAsynchronous?=?async;

}

通過Looper.myLooper()獲取了當(dāng)前線程保存的Looper實例敞映,然后在mQueue = mLooper.mQueue;又獲取了這個Looper實例中保存的MessageQueue(消息隊列),這樣就保證了handler的實例與我們Looper實例中MessageQueue關(guān)聯(lián)上了磷斧。


了解完了looper和handler我們總結(jié)一下吧

1振愿、首先Looper.prepare()在本線程中保存一個Looper實例,然后該實例中保存一個MessageQueue對象弛饭;因為Looper.prepare()在一個線程中只能調(diào)用一次冕末,所以MessageQueue在一個線程中只會存在一個。

2侣颂、Looper.loop()會讓當(dāng)前線程進入一個無限循環(huán)(如果沒有消息則阻塞)档桃,不端從MessageQueue的實例中讀取消息,然后回調(diào)msg.target.dispatchMessage(msg)方法憔晒。

3藻肄、Handler的構(gòu)造方法,會首先得到當(dāng)前線程中保存的Looper實例拒担,進而與Looper實例中的MessageQueue想關(guān)聯(lián)仅炊。

4、Handler的sendMessage方法澎蛛,會給msg的target賦值為handler自身,然后加入MessageQueue中蜕窿。

5谋逻、在構(gòu)造Handler實例時,我們會重寫handleMessage方法桐经,也就是msg.target.dispatchMessage(msg)最終調(diào)用的方法毁兆。

總結(jié)完畢.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市阴挣,隨后出現(xiàn)的幾起案子气堕,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茎芭,死亡現(xiàn)場離奇詭異揖膜,居然都是意外死亡,警方通過查閱死者的電腦和手機梅桩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門壹粟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人宿百,你說我怎么就攤上這事趁仙。” “怎么了垦页?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵雀费,是天一觀的道長。 經(jīng)常有香客問我痊焊,道長盏袄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任宋光,我火速辦了婚禮貌矿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘罪佳。我一直安慰自己逛漫,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布赘艳。 她就那樣靜靜地躺著酌毡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蕾管。 梳的紋絲不亂的頭發(fā)上枷踏,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天,我揣著相機與錄音掰曾,去河邊找鬼旭蠕。 笑死,一個胖子當(dāng)著我的面吹牛旷坦,可吹牛的內(nèi)容都是我干的掏熬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼秒梅,長吁一口氣:“原來是場噩夢啊……” “哼旗芬!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起捆蜀,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤疮丛,失蹤者是張志新(化名)和其女友劉穎幔嫂,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體誊薄,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡履恩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了暇屋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片似袁。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖咐刨,靈堂內(nèi)的尸體忽然破棺而出昙衅,到底是詐尸還是另有隱情,我是刑警寧澤定鸟,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布而涉,位于F島的核電站,受9級特大地震影響联予,放射性物質(zhì)發(fā)生泄漏啼县。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一沸久、第九天 我趴在偏房一處隱蔽的房頂上張望季眷。 院中可真熱鬧,春花似錦卷胯、人聲如沸子刮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挺峡。三九已至,卻和暖如春担钮,著一層夾襖步出監(jiān)牢的瞬間橱赠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工箫津, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留狭姨,地道東北人。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓苏遥,卻偏偏與公主長得像送挑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子暖眼,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,871評論 2 354

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