Android Handler的使用

Android Handler算是一個(gè)很神奇的東西吧,為什么這么說呢,因?yàn)閯傞_始學(xué)習(xí)Android的時(shí)候講師就一值在說Handler的重要性,下面就來看看對(duì)Handler的淺度理解吧:

一.什么是Handler

?Handler是Android給我們提供用來更新UI的一套機(jī)制,是一套消息處理機(jī)制,可以通過它來發(fā)送消息和處理消息。那作為開發(fā)者的我們,不禁會(huì)疑問?Google為什么要設(shè)計(jì)這套機(jī)制呢?這是為了解決在非UI線程中更新UI組件比較麻煩的問題。那么Android為什么不能在非UI線程中更新呢?首先Android的UI控件不是線程安全的,這是因?yàn)楸苊舛嗑€程并發(fā)所帶來不安全問題。例如作一個(gè)假設(shè),現(xiàn)在在子線程中刷新界面,同時(shí)也在UI線程中刷新界面,就會(huì)出現(xiàn)刷新不同步,簡(jiǎn)單來講通過Handler就可以更新UI操作切換到主線程中執(zhí)行。


二.Handler機(jī)制

?Handler機(jī)制主要角色

Message:消息,就是一個(gè)載體,包含消息ID,消息處理對(duì)象和處理的數(shù)據(jù)等,統(tǒng)一放到MessageQueue,最終由Handler處理。

Handler:用于同一個(gè)進(jìn)程的線程間通信,消息處理者,專門負(fù)責(zé)Message的發(fā)送和處理。我們使用Handler時(shí),一般通過handleMessage(Message msg)來處理Message,也就是統(tǒng)一處理消息的回調(diào),確保自己發(fā)出的消息也是自己來處理。

MessageQueue:由名字可推出這是隊(duì)列,就是存放Handler發(fā)送過來的消息,按照先進(jìn)先出的順序規(guī)則來執(zhí)行。將鏈表的數(shù)據(jù)結(jié)構(gòu)以Message來串聯(lián)起來,等待Looper的抽取,為什么需要隊(duì)列呢?因?yàn)橥痪€程在一個(gè)時(shí)間只能處理一個(gè)消息。因此需要隊(duì)列來保存這些消息,然后挨個(gè)挨個(gè)拿出來處理,創(chuàng)建一個(gè)線程時(shí)并不會(huì)自動(dòng)創(chuàng)建MessageQueue,但是主線程創(chuàng)建時(shí)會(huì)默認(rèn)創(chuàng)建Looper對(duì)象,而Looper創(chuàng)建時(shí)就會(huì)創(chuàng)建MessageQueue,其他非主線程需要looper的時(shí)候就會(huì)通過調(diào)用prepare函數(shù)來實(shí)現(xiàn)。

Looper:首先要理解一個(gè)線程是一段可執(zhí)行的代碼,作為App的主線程,不能讓代碼執(zhí)行完,因?yàn)榇a執(zhí)行完的話app就會(huì)自動(dòng)退出,因此不能讓主線程不能讓代碼段執(zhí)行,只能在代碼中插入一個(gè)死循環(huán),這時(shí)候Looper的作用就體現(xiàn)出來了,將主線程變成Looper線程。并且這時(shí)主線程就會(huì)在等其他線程發(fā)消息(更新UI和Activity狀態(tài)等等)那,另外,Looper不斷從消息隊(duì)列拿出消息給主線程,也就是無限循環(huán)去查找是否有消息,有就去處理,沒有的話就一直等待,一個(gè)MessageQueue需要一個(gè)Looper。

Thread:負(fù)責(zé)調(diào)度整個(gè)消息的循環(huán)。

通過上面可以得知:Handler的作用是發(fā)送和處理消息,Handler發(fā)送的消息必須被送到指定MessageQueue中,也就是說,要讓Handler正常工作就必須有一個(gè)MessageQueue,但是MessageQueue是由Looper來抽取自身的Message,也因此當(dāng)前線程中必須有一個(gè)Looper對(duì)象。

圖解:


Handler深度理解

根據(jù)上面可得:每一個(gè)線程都必須有Looper,但是我們不禁會(huì)有疑問?主線程我們并沒有創(chuàng)建Looper?其實(shí)主線程是ActivityThread,ActivityThread被創(chuàng)建的時(shí)候就會(huì)初始化Looper。


上面紅色箭頭就是主線程創(chuàng)建Looper對(duì)象代碼語句。那么我們繼續(xù)進(jìn)入Looper去看看究竟是什么操作。


果然上面所分析的幾個(gè)主要角色都在:Looper,MessageQueue,Thread,但是還多了一個(gè)ThreadLocal,這個(gè)是什么呢?其實(shí)這個(gè)是一個(gè)線程內(nèi)部的數(shù)據(jù)存儲(chǔ)類,通過它可以在指定線程中存儲(chǔ)數(shù)據(jù),數(shù)據(jù)存儲(chǔ)以后,只有在指定的線程獲取到存儲(chǔ)數(shù)據(jù),對(duì)于其他線程來說則無法獲取到數(shù)據(jù),后面例子再詳細(xì)敘述。

這時(shí)候又有疑問,為什么主線程中有一個(gè)死循環(huán),但是沒有造成阻塞呢?那我們從ActivityThread類開始分析:這個(gè)并不是一個(gè)真正的線程,就只是一個(gè)類,從main方法看到有Looper,那找找其對(duì)應(yīng)的Handler,ActivityThread有一個(gè)內(nèi)部類,繼承Handler,并找到handleMessage


仔細(xì)觀察:Activity的生命周期都有對(duì)應(yīng)的case條件,并且service的生命周期等等都有條件。也就是通過loop來分發(fā)消息內(nèi)部類的Handler,就會(huì)進(jìn)入handleMessage。就會(huì)根據(jù)對(duì)應(yīng)的條件來執(zhí)行對(duì)應(yīng)的代碼,不斷執(zhí)行傳遞過來的消息。那么可以總結(jié)來說:ActivityThread的main方法主要是來做消息循環(huán)的,如果消息循環(huán)退出了,那么程序就退出了。但是從隊(duì)列里取出消息可能會(huì)造成阻塞,如果某個(gè)消息處理的時(shí)間過于長(zhǎng),那么會(huì)影響UI線程的刷新,就造成卡頓現(xiàn)象。不會(huì)造成卡在的真正原因主要有二:

1.當(dāng)沒有消息來的時(shí)候就會(huì)wait,有句柄寫的時(shí)候就會(huì)喚醒,進(jìn)行等待。

2.所有的UI更新操作都通過handler來發(fā)消息。如各種的點(diǎn)擊事件都會(huì)造成句柄寫的操作來喚醒等待。

主線程是UI線程,優(yōu)先級(jí)很高,主線程的死循環(huán)會(huì)不會(huì)特別消耗CPU資源呢?

其實(shí)如果主線程的隊(duì)列里沒有消息時(shí),就會(huì)阻塞在loop的queue.next()里,這時(shí)候主線程就會(huì)釋放CPU資源進(jìn)入休眠狀態(tài),直到下個(gè)消息進(jìn)來時(shí)就會(huì)喚醒主線程,現(xiàn)在是通過pipe管道來寫入數(shù)據(jù),類似I/0,不占用資源。


三.例子實(shí)踐

下面簡(jiǎn)單寫一個(gè)小例子加深理解:

倒計(jì)時(shí)例子:

public

classMainActivityextendsActivity{

privateTextView text_one;

privatemHandler mhandler =newmHandler(this);

@Override

protectedvoidonCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);

? ? ? ? setContentView(R.layout.activity_main);

? ? ? ? text_one = findViewById(R.id.text_one);

? ? ? ? start();

? ? }

//Handler靜態(tài)內(nèi)部類 防止內(nèi)存泄漏

privatestaticclassmHandlerextendsHandler{

? ? ? WeakReference<MainActivity> weakReference;

publicmHandler(MainActivity mainActivity){

weakReference =newWeakReference(mainActivity);

? ? ? }

@Override

publicvoidhandleMessage(Message msg){

? ? ? ? ? MainActivity mainActivity = weakReference.get();

if(mainActivity !=null){

? ? ? ? ? ? ? ? mainActivity.text_one.setText(String.valueOf(msg.arg1));

? ? ? ? ? }

? ? ? }

? ? }

privatevoidstart(){

newThread(newRunnable() {

@Override

publicvoidrun(){

for(inti =10;i>0;i--){

Message msg =newMessage();

msg.what =01;

? ? ? ? ? ? ? ? ? ? msg.arg1 = i;

? ? ? ? ? ? ? ? ? ? mhandler.sendMessage(msg);

try{

Thread.sleep(1000);

}catch(InterruptedException e) {

? ? ? ? ? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

//計(jì)時(shí)結(jié)束后先不管

? ? ? ? ? ? }

? ? ? ? }).start();

? }

@Override

protectedvoidonDestroy(){

super.onDestroy();

if(mhandler !=null){

mhandler.removeCallbacksAndMessages(null);

? ? ? }

? }

以上就是對(duì)Handler的理解,謝謝觀看!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容