導航:首頁 > 使用方法 > androidhandler使用方法

androidhandler使用方法

發布時間:2023-01-06 03:55:07

A. Android Handler機制 怎麼

Handler對象與其調用者在同一線程中,如果在Handler中設置了延時操作,則調用線程也會堵塞。每個Handler對象都會綁定一個Looper對象,每個Looper對象對應一個消息隊列(MessageQueue)。如果在創建Handler時不指定與其綁定的Looper對象,系統默認會將當前線程的Looper綁定到該Handler上。
在主線程中,可以直接使用new Handler()創建Handler對象,其將自動與主線程的Looper對象綁定;在非主線程中直接這樣創建Handler則會報錯,因為Android系統默認情況下非主線程中沒有開啟Looper,而Handler對象必須綁定Looper對象。這種情況下,需先在該線程中手動開啟Looper(Looper.prepare()-->Looper.loop()),然後將其綁定到Handler對象上;或者通過Looper.getMainLooper(),獲得主線程的Looper,將其綁定到此Handler對象上。
Handler發送的消息都會加入到Looper的MessageQueue中。一說Handler包含兩個隊列:線程隊列和消息隊列;使用Handler.post()可以將線程對象加入到線程隊列中;使用Handler.sendMessage()可以將消息對象加入到消息隊列中。通過源碼分析證實,Handler只有一個消息隊列,即MessageQueue。通過post()傳進去的線程對象將會被封裝成消息對象後傳入MessageQueue。
使用post()將線程對象放到消息隊列中後,當Looper輪詢到該線程執行時,實際上並不會單獨開啟一個新線程,而仍然在當前Looper綁定的線程中執行,Handler只是調用了該線程對象的run()而已。如,在子線程中定義了更新UI的指令,若直接開啟將該線程執行,則會報錯;而通過post()將其加入到主線程的Looper中並執行,就可以實現UI的更新。
使用sendMessage()將消息對象加入到消息隊列後,當Looper輪詢到該消息時,就會調用Handler的handleMessage()來對其進行處理。再以更新UI為例,使用這種方法的話,就先將主線程的Looper綁定在Handler對象上,重載handleMessage()來處理UI更新,然後向其發送消息就可以了。

B. Android面試必問handler機制淺析

Handler是Android中的非同步消息處理機制。當發送一個消息之後,這個消息是進入一個消息隊列(MessageQueue),在消息隊列中通過Looper去循環的獲取隊列中的消息,然後將消息分派給對應的處理者進行處理。

Message:存儲需要處理操作的信息

MessageQueue:先進先出,存儲handler發送過來的消息

Looper:循環器,它是消息隊列和handler的通信媒介,1:循環的取出消息隊列中的消息;2:將取出的消息發送給對應的處理者

Handler:主線程和子線程的通信媒介,1:添加消息到消息隊列; 2:處理循環器分派過來的消息

在handler機制中,Looper.loop方法會不斷循環獲取Message, 其中的消息的獲取是通過調用MessageQueue的next()方法獲取的,而該方法會調用nativePollOnce()方法 ,這是一個native方法。底層的實現涉及到Linux pipe/epoll機制,nativePollOnce()被阻塞時,主線程會釋放CPU資源,進入休眠狀態. 直到下個消息到達或者有事務發生,會通過pipe管道寫端寫入數據來喚醒looper工作。

Android6.0及以前的版本使用管道與epoll來完成Looper的休眠與喚醒的

Android6.0及以後的版本使用eventfd與epoll來完成Looper的休眠與喚醒的

如果不處理的話,會阻塞線程,處理方案是調用Looper的quit()(清空所有的延遲和非延遲的消息)和quitSafely()(只清空延遲消息); 這個方法會調用MessageQueue的quit()方法,清空所有的Message,並調用nativeWake()方法喚醒之前被阻塞的nativePollOnce(),使得方法next()方法中的for循環繼續執行,接下來發現Message為null後就會結束循環,Looper結束。如此便可以釋放內存和線程

同進程線程間內存共享,通過handler通信,消息的內容是不需要從一個線程拷貝到另一個線程,因為兩個線程間可使用的內存是同一個區域。(注意:線程私有區域ThreadLocal)

管道的作用就是當一個線程准備好Message,並放入消息池,這時需要通知了一個線程B去處理這個消息。線程A向管道的寫端寫入數據,管道有數據便會喚醒線程B去處理消息。管道的作用是用於通知另一個線程的,這便是最核心的作用。

從內存角度,通信過程中binder涉及到一次內存拷貝,handler機制中的Message根本不需要拷貝,本身就是在同一片內存。

從CPU角度,為了Binder通信底層驅動還需要創建一個binder線程池,每次通信涉及binder線程的創建和內存的分配等比較浪費CPU資源

原因:handler發送的消息在當前handler的消息隊列中,如果此時activity被finish掉了,那麼消息隊列的消息依舊由handler進行處理,若此時handler申明為內存類(非靜態內部類),內部類持有外部類的實例引用,這樣在GC垃圾回收時發現Activity還有其他引用存在,因而就不會去回首這個Activity,進而導致Activity泄漏。

方法:使用靜態內部類,並且使用WeakReference包裹外部類的對象。首先靜態內部類不持有外部類的引用,使用靜態的handler不會導致activity的泄漏,handler定義static的同時,還要用WeakReference包裹外部類的對象。

C. Android Handler使用

在日常開發中,都避免不了進行網路請求,並更新View,由於Android中主線程不可以進行耗時操作,所以我們的網路請求只能放在子線程中,又由於在子線程中不能更新UI,所以我們就需要使用Handler切換到主線程並更新UI。

在介紹Handler使用之前,我們先了解以下兩個問題。

1、為什麼主線程不能進行耗時操作?
因為如果在主線程進行耗時操作,容易出現ANR,Application Not Responding,即應用無響應,當在一定的時間內,app無法響應時就會出現ANR,並彈出一個 對話框提示應用無響應,所以我們應該避免在主線程中進行耗時操作,當我們應用出現ANR時,會在
/data/anr/目錄中生成traces.txt,我們可以通過這個文件查找錯誤信息。

2、為什麼子線程中不能更新UI?
這是因為在子線程中更新UI不是線程安全的,在Android源碼ViewRootImpl的checkThread方法中也對UI做了驗證。

基於這兩個問題,我們可以使用Handler來解決,接下來介紹Handler的基本使用。

首先創建Handler

接下來發送消息。

這個時候在handlerMessage方法中即可收到消息,獲取Message中的數據,並更新UI了。是不是很簡單。

D. Android中的Handler機制

Handler常用於Android中線程間通信
消息處理流程有一張圖可以參考下

這里有幾個重要的關鍵點(按我自己理解翻譯的一下)
1.Message:消息
2.MessageQueue:消息隊列
3.Handler:消息處理器,負責消息的收發,可以存在多個
4.Looper:循環消息分發器

通信嘛,要先有傳遞的信息Message

MessageQueue,消息同時發又處理不完又需要保持同步,於是有了消息隊列,讓消息按順序處理

Looper,消息分發器,在其loop()後會循環消息隊列去取消息進行分發處理,如果沒有則會阻塞

最後是Handler,負責消息的收發處理,sendMessage發送消息,重寫handleMessage方法即可處理收到的消息(這里主線程直接獲取了looper)如果是子線程則需要先對Looper就行初始化

介紹完功能來順一下流程
首先主線程中ActivityThread中main方法創建了Looper

這里進入Looper

當我們需要傳遞消息時
通過獲取對應線程Looper來初始化Handler,

初始化一個消息,Message.obtain()來獲得而不是new一個Message,因為Message內部有一個消息池子,消息收到處理後,內部信息清除就可以重復使用,避免資源浪費。

然後插入到Handler所在的消息隊列

然後Loop發現有新消息,派發到對應的Handler來處理消息dispatchMessage

Handler.dispatchMessage,先判斷是否有callback(即Runnable),如果有走handleCallback,否則執行handleMessage

簡單總計一下:
線程間通信每個線程都需要初始化Looper和消息隊列,Loop不停向消息隊列讀取消息,通過不同線程的Handler來發送信息,如A線程有1,2兩個Hander,B線程有3,4兩個Hander,A線程調用3,4來發送信息,B線程即可收到 A線程發來的信息

閱讀全文

與androidhandler使用方法相關的資料

熱點內容
做糖最簡便的方法 瀏覽:638
草酸的檢測方法國標 瀏覽:846
如何提高寫作水平有哪些方法 瀏覽:502
最簡單的溫柔方法 瀏覽:362
oppor4耗電快解決方法 瀏覽:607
塵埃粒子計數器使用方法 瀏覽:767
打鼓方法與技巧 瀏覽:876
陰部按摩器使用方法 瀏覽:877
迷迭香的使用方法 瀏覽:83
嗜鉻細胞瘤的治療方法有哪些 瀏覽:618
如何除濕疹最有效的方法 瀏覽:527
自製池塘簡單方法 瀏覽:707
電泳檢測的方法 瀏覽:789
工業cod檢測方法 瀏覽:299
星辰變的種植方法 瀏覽:605
商品組合需求預測有哪些方法 瀏覽:966
卷發精油的使用方法 瀏覽:577
快速識字方法 瀏覽:189
華為大疆手機雲台使用方法 瀏覽:503
小學語文有效教學方法之探析 瀏覽:563