欧美成人午夜免费全部完,亚洲午夜福利精品久久,а√最新版在线天堂,另类亚洲综合区图片小说区,亚洲欧美日韩精品色xxx

扣丁學(xué)堂解析Android 異步消息分發(fā)機(jī)制

2018-09-04 10:36:53 1434瀏覽

隨著互聯(lián)網(wǎng)IT行業(yè)的發(fā)展,越來越多的人選擇入坑互聯(lián)網(wǎng),程序員是一個很好的選擇,但是很多沒有基礎(chǔ)的同學(xué)都會選擇先去培訓(xùn)機(jī)構(gòu)培訓(xùn),今天小編先來給大家講一下Android異步消息分發(fā)機(jī)制。



Android的消息機(jī)制

–主要是指Handler的運行機(jī)制和MessageQueue、looper的工作過程。

MessageQueue

MessageQueue消息隊列,用來存儲消息,雖然稱為消息隊列,但是它的存儲結(jié)構(gòu)是采用單鏈表的數(shù)據(jù)結(jié)構(gòu)來存儲消息隊列的。

包含兩個操作插入(enqueueMessage)和讀?。╪ext)

enqueueMessage:往消息鏈表中插入一條信息

next:從消息列表中讀取一天消息,并將其從消息隊列中移除,next方法是一個無限循環(huán)的方法,如果消息列表里沒有消息,那么會一直阻塞在這里。

Looper

Looper消息循環(huán),用來處理消息。

Looper會不停的從MessageQueue中查看是否有新的消息,如果有新消息就會立即處理

Looper.java

privateLooper(booleanquitAllowed){

mQueue=newMessageQueue(quitAllowed);

mThread=Thread.currentThread();

}

在Looper的構(gòu)造方法會創(chuàng)建一個MessageQueue,消息隊列,然后將當(dāng)前線程的對象保存起來。

publicstatic@NullableLoopermyLooper(){

returnsThreadLocal.get();

}

privatestaticvoidprepare(booleanquitAllowed){

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

thrownewRuntimeException("OnlyoneLoopermaybecreatedperthread");

}

sThreadLocal.set(newLooper(quitAllowed));

}

問題為什么Looper.prepare()不能被調(diào)用兩次?

答:因為每次調(diào)用Looper.prepare()的時候的都會判斷ThreadLocal是否已經(jīng)存儲當(dāng)前的Looper對象,如果已經(jīng)存在就會拋出異常。

/**

*Runthemessagequeueinthisthread.Besuretocall

*{@link#quit()}toendtheloop.

*/

publicstaticvoidloop(){

finalLooperme=myLooper();

if(me==null){

thrownewRuntimeException("NoLooper;Looper.prepare()wasn'tcalledonthisthread.");

}

finalMessageQueuequeue=me.mQueue;

//Makesuretheidentityofthisthreadisthatofthelocalprocess,

//andkeeptrackofwhatthatidentitytokenactuallyis.

Binder.clearCallingIdentity();

finallongident=Binder.clearCallingIdentity();

for(;;){

Messagemsg=queue.next();//mightblock

if(msg==null){

//Nomessageindicatesthatthemessagequeueisquitting.

return;

}

//Thismustbeinalocalvariable,incaseaUIeventsetsthelogger

finalPrinterlogging=me.mLogging;

if(logging!=null){

logging.println(">>>>>Dispatchingto"+msg.target+""+

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

}

finallongtraceTag=me.mTraceTag;

if(traceTag!=0&&Trace.isTagEnabled(traceTag)){

Trace.traceBegin(traceTag,msg.target.getTraceName(msg));

}

try{

msg.target.dispatchMessage(msg);

}finally{

if(traceTag!=0){

Trace.traceEnd(traceTag);

}

}

if(logging!=null){

logging.println("<<<<<Finishedto"+msg.target+""+msg.callback);

}

//Makesurethatduringthecourseofdispatchingthe

//identityofthethreadwasn'tcorrupted.

finallongnewIdent=Binder.clearCallingIdentity();

if(ident!=newIdent){

Log.wtf(TAG,"Threadidentitychangedfrom0x"

+Long.toHexString(ident)+"to0x"

+Long.toHexString(newIdent)+"whiledispatchingto"

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

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

}

msg.recycleUnchecked();

}

}

loop方法就是一個死循環(huán),跳出死循環(huán)的方法,是MessageQueue的Next方法為空,即queue.next()為空。Looper調(diào)用quit方法或者quitSafely方法,通知消息隊列退出,會使MessageQueue的next方法返回為空。

loop調(diào)用MessageQueue的next方法獲取新的消息,如果沒有消息,next方法會一直阻塞在那里,導(dǎo)致loop方法也會一直阻塞在那里。如果next方法返回了新的消息,Looper就會處理新的消息,調(diào)用msg.target.dispatchMessage(msg),msg.target就是發(fā)送這條消息的Handler對象(Handler中有講解)。這樣就把代碼邏輯切換到指定線程去執(zhí)行了。

3.ThreadLocal

線程內(nèi)部的數(shù)據(jù)存儲類,通過它可以在指定的線程存儲數(shù)據(jù),而且存儲后,只能在指定線程獲取存儲的數(shù)據(jù),其他線程無法獲取。

應(yīng)用:當(dāng)某些數(shù)據(jù)是以線程為作用域,并且不同線程具有不同數(shù)據(jù)

存在Looper中,并不是線程,作用是在每個線程中存儲數(shù)據(jù)

問題:Handler內(nèi)部是如何獲取當(dāng)前線程的Looper的?

Handler.java

publicHandler(Callbackcallback,booleanasync){

if(FIND_POTENTIAL_LEAKS){

finalClass<?extendsHandler>klass=getClass();

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

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

Log.w(TAG,"ThefollowingHandlerclassshouldbestaticorleaksmightoccur:"+

klass.getCanonicalName());

}

}

mLooper=Looper.myLooper();

if(mLooper==null){

thrownewRuntimeException(

"Can'tcreatehandlerinsidethreadthathasnotcalledLooper.prepare()");

}

mQueue=mLooper.mQueue;

mCallback=callback;

mAsynchronous=async;

}

答:Handler通過ThreadLocal獲取每個線程的Looper.ThreadLocal可以在不同線程中互不干擾的存儲并提供數(shù)據(jù)。

在調(diào)用Looper.prepare()的時候“sThreadLocal.set(newLooper(quitAllowed));”-創(chuàng)建了一個Looper實例并將一個Looper的實例放入了ThreadLocal存儲。然后在Handler中調(diào)用“mLooper=Looper.myLooper();”-從sThreadLocal.get()獲取到Looper對象。

問題:主線程中為什么可以默認(rèn)使用Handler?

答:線程默認(rèn)是沒有Looper的,如果要使用Handler,就必須為線程創(chuàng)建Looper.但是主線程,也就是UI線程,它就是ActivityThread,ActivityThread被創(chuàng)建的時候默認(rèn)會初始化Looper,當(dāng)前UI線程調(diào)用了Looper.prepare()和Looper.loop()方法.

4.Handler

主要工作:發(fā)送和接收消息;

publicfinalbooleansendMessage(Messagemsg)

{

returnsendMessageDelayed(msg,0);

}

publicfinalbooleansendMessageDelayed(Messagemsg,longdelayMillis)

{

if(delayMillis<0){

delayMillis=0;

}

returnsendMessageAtTime(msg,SystemClock.uptimeMillis()+delayMillis);

}

publicbooleansendMessageAtTime(Messagemsg,longuptimeMillis){

MessageQueuequeue=mQueue;

if(queue==null){

RuntimeExceptione=newRuntimeException(

this+"sendMessageAtTime()calledwithnomQueue");

Log.w("Looper",e.getMessage(),e);

returnfalse;

}

returnenqueueMessage(queue,msg,uptimeMillis);

}

privatebooleanenqueueMessage(MessageQueuequeue,Messagemsg,longuptimeMillis){

msg.target=this;

if(mAsynchronous){

msg.setAsynchronous(true);

}

returnqueue.enqueueMessage(msg,uptimeMillis);

}

由上面可以看出Handler發(fā)送消息的過程就是向消息鏈表中插入了一條消息,MessageQueue的next方法會返回這條消息給Looper,Looper收到消息,通過msg.target.dispatchMessage(msg)交給Handler處理。

上面enqueueMessage方法首先“msg.target=this;”會把this賦值給msg.target,也就是說把Handler賦值給msg的target屬性。

publicvoiddispatchMessage(Messagemsg){

if(msg.callback!=null){

handleCallback(msg);

}else{

if(mCallback!=null){

if(mCallback.handleMessage(msg)){

return;

}

}

handleMessage(msg);

}

}

首先會檢查Message的callback是否為null,不為空就處理通過handleCallback來處理消息。

callback是一個Runnable接口,就是Handler的post方法傳遞的Runnable參數(shù)

privatestaticvoidhandleCallback(Messagemessage){

message.callback.run();

}

舉個栗子第一種handler的使用方式,post方法

HandlermHandler=newhandler();

mHandler.post(newRunnable()

{

@Override

publicvoidrun()

{

Log.e("TAG",Thread.currentThread().getName());

mTxt.setText("yoxi");

}

});

其次查看mCallback是否為空,mCallback是個接口

publicinterfaceCallback{

publicbooleanhandleMessage(Messagemsg);

}

Callback提供另一種使用Handler的方式,不想派生Handler的子類,可以通過Callback來實現(xiàn)。

舉個栗子第二種使用Handler的方式

privateHandlermHandler=newHandler()

{

publicvoidhandleMessage(android.os.Messagemsg)

{

switch(msg.what)

{

casevalue:

break;

default:

break;

}

};

};

最后,調(diào)用Handler的handleMessage方法來處理消息。


以上就是扣丁學(xué)堂Android在線學(xué)習(xí)小編給大家分享的Android模擬器相關(guān)的內(nèi)容,希望對小伙伴們有所幫助,想要了解更多內(nèi)容的小伙伴可以登錄扣丁學(xué)堂官網(wǎng)咨詢。想要學(xué)好Android開發(fā)小編給大家推薦口碑良好的扣丁學(xué)堂,扣丁學(xué)堂有專業(yè)老師制定的Android學(xué)習(xí)路線圖輔助學(xué)員學(xué)習(xí),此外還有與時俱進(jìn)的Android課程體系和大量的Android視頻教程供學(xué)員觀看學(xué)習(xí),想要學(xué)好Android開發(fā)技術(shù)的小伙伴快快行動吧。

扣丁學(xué)堂微信公眾號

【關(guān)注微信公眾號獲取更多學(xué)習(xí)資料】



查看更多關(guān)于“Android開發(fā)技術(shù)的相關(guān)資訊>>


標(biāo)簽: Android培訓(xùn)

熱門專區(qū)

暫無熱門資訊

課程推薦

微信
微博
15311698296

全國免費咨詢熱線

郵箱:codingke@1000phone.com

官方群:148715490

北京千鋒互聯(lián)科技有限公司版權(quán)所有   北京市海淀區(qū)寶盛北里西區(qū)28號中關(guān)村智誠科創(chuàng)大廈4層
京ICP備2021002079號-2   Copyright ? 2017 - 2022
返回頂部 返回頂部