想要了解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é)完畢.