androidhandler機制
1. 【Android】Message、Handler、MessageQueue、Looper 詳解
Handler在Android中主要應用於跨線程通信,確保線程A與線程B之間能夠通過共享同一個Handler對象進行消息傳遞與接收。Handler家族主要包括Message、Handler、MessageQueue與Looper。此框架通過Looper啟動消息循環,Handler生成消息,MessageQueue存儲消息,Looper處理消息,形成一套高效的消息處理機制。
消息生成與處理的關鍵在於Message類,其內部維護著一個可用消息對象池(sPool),此池實質上是一個鏈表結構,sPool指向鏈表頭結點,而next則指向下一個節點。當Handler生成消息時,會將自身作為Message的target,與Message對象綁定。Handler發送消息的途徑主要通過enqueueMessage方法,確保每個msg均能綁定一個Handler實例。消息處理則通過Looper循環執行,按照dispatchMessage方法的順序進行。
Handler家族中的Looper負責創建與管理消息隊列,消息隊列通過MessageQueue存儲待處理的消息。Looper循環執行,從MessageQueue取出消息並進行處理。Looper在主線程中自動創建,而在子線程中則需手動傳入Looper對象。
在應用層面,Handler機制可以實現主線程與子線程間的通信。例如,主線程負責處理消息,子線程負責發送消息。這種機制在很多場景下都非常有用,但有時可能需要實現主線程與子線程之間的通信,或者多個子線程之間的通信。這時,可以使用HandlerThread類來實現。
HandlerThread類提供了一種創建子線程並自動啟動消息循環的方式,允許主線程向子線程發送消息。實現過程主要包括創建HandlerThread實例、啟動線程並創建Looper對象、以及通過Handler對象在子線程中發送消息。這種方式使得多線程間的消息傳遞更加靈活與高效。
2. Android:在一個非主線程內直接調用UI線程的Handler實例,這樣沒問題嗎
在Android開發中,我們常常遇到線程安全的問題,特別是在子線程和UI線程之間進行交互時。為了保證應用程序的穩定性和用戶體驗,我們不能直接在子線程中更新UI線程中的UI元素。為了解決這個問題,Android提供了一種機制——Handler。
Handler的工作原理是這樣的:當子線程需要更新UI線程中的UI元素時,它會通過發送消息的方式,將需要更新的內容傳遞給UI線程。這些消息會被放入UI線程的消息隊列中,然後由UI線程中的Handler逐個處理。這樣,我們就可以在子線程中執行耗時操作,同時在UI線程中更新UI,從而保證了界面的流暢性。
在Android中,創建多線程的方式主要有兩種:一種是通過繼承Thread類並重寫run方法;另一種是通過實現Runnable介面並實現run方法。無論哪種方式,子線程都無法直接修改UI線程中的UI元素,而Handler正是用來解決這一問題的關鍵。
Handler的主要方法包括post、postAtTime、postDelayed、sendEmptyMessage、sendMessage、sendMessageAtTime、sendMessageDelayed等。這些方法分別用於在主線程中執行Runnable或發送消息。通過這些方法,我們可以靈活地控制消息的發送時機和執行方式。
下面,我們通過一個簡單的例子來說明Handler的使用方法。假設我們需要在主線程中的TextView中顯示10到100之間的隨機數,每隔5秒更新一次,總共更新5次。主要代碼如下:
java
int i = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler.post(run);
}
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg){
String s = String.valueOf(msg.what);
TextView tv = (TextView)findViewById(R.id.textView);
tv.setText(tv.getText() + " " + s);
}
};
Runnable run = new Runnable(){
@Override
public void run(){
Random r = new Random();
int rnum = r.nextInt((100 - 10) + 1) + 10;
handler.sendEmptyMessage(rnum);
handler.postDelayed(run, 5000);
i++;
if (i==5){
handler.removeCallbacks(run);
}
}
};
通過這個例子,我們可以看到Handler在處理子線程與UI線程之間的交互時的重要作用。在實際開發中,我們可以根據具體需求,靈活地使用Handler的各種方法來實現復雜的線程交互邏輯。
3. Android組件系列:再談Handler機制(Native篇)
前文已介紹過Java層Handler機制的設計與實現,本篇將深入探討Native層的Looper#loop()為何不會卡死主線程的原理。
從Android 2.3版本開始,Google將Handler的阻塞/喚醒機制從Object#wait() / notify()改為了利用Linux epoll來實現,為的是在Native層引入一套消息管理機制,以支持C/C++開發者。
在Native層實現類似Java層的阻塞/喚醒機制,主要面臨兩種選擇:要麼繼續使用Object#wait() / notify(),通過Java層通知Native層何時喚醒;要麼在Native層重新實現一套阻塞/喚醒方案,並通過JNI調用Java層進入阻塞態。最終,Google選擇了後者。
雖然將Java層的阻塞/喚醒機制直接移植到Native層並非必要,使用pthread_cond_wait也能實現相同效果,但epoll提供了一種更高效、更靈活的方案,特別是對於監聽多個流事件的需求。
理解I/O多路復用之epoll
epoll是Linux I/O多路復用實現之一,與select和poll並列。它能夠高效地同時監聽多個流事件,而無需為每個流創建單獨的線程或阻塞CPU資源。
epoll通過將流事件轉發到用戶空間,讓用戶程序能實時響應事件。為了實現這一功能,epoll與eventfd配合使用。eventfd提供了一個用於累計計數的特殊文件描述符,只有當有新事件發生時,用戶程序才能從eventfd中讀取到計數增加。
Native Handler機制解析
Native層Handler機制的核心是Looper、MessageQueue和epoll+eventfd的組合。以下是關鍵步驟:
消息隊列初始化
消息隊列初始化涉及創建Looper對象,該對象持有mEpollFd和mWakeEventFd兩個關鍵對象。mWakeEventFd用於監聽消息隊列的新消息,而mEpollFd用於管理監聽的流事件。
消息循環與阻塞
Java和Native層的消息隊列創建後,線程將阻塞在Looper#loop()方法中。在Java層,消息隊列的循環與阻塞由nativePollOnce()方法實現,最終調用到NativeMessageQueue#pollOnce()方法。這個方法將請求轉發給Looper#pollOnce()方法執行。
消息發送與喚醒機制
發送消息時,無論是Java還是Native層,最終都會調用到喚醒線程的方法。Java中,通過nativeWake()方法喚醒,而Native層直接通過write()方法向mWakeEventFd寫入值來喚醒線程。
喚醒後的消息分發處理
線程喚醒後,首先判斷喚醒原因,然後根據不同的情況執行相應的邏輯。關鍵步驟包括檢查mWakeEventFd、處理Native層消息、處理自定義fd的事件等。
結語
通過深入理解epoll機制及其與Native Handler的集成,我們可以清晰地理解Handler機制的底層實現。理解了這些關鍵技術點後,開發者能夠更深入地掌握並優化Android應用中的消息處理邏輯。
4. android之Handler處理機制
在深入研究Handler之前,讓我們先思考幾個關鍵問題:
1. Handler的必要性
Android設計Handler機制的主要目的是解決多線程並發中的UI更新問題。設想在一個Activity中,多個線程試圖並行更新UI,如果沒有恰當處理,會導致界面混亂。而對所有UI操作強制加鎖會犧牲性能。
2. Handler的作用
為了解決上述問題,Android提供了一套機制,讓所有的UI更新都在主線程的消息隊列中非同步處理,無需開發者直接關心並發問題。Handler就是實現這一機制的關鍵。
3. Handler工作原理
Handler與通信的非同步同步概念相關。它就像一個非同步回調的執行者,子線程通過Handler向主線程發送消息,這些消息在MessageQueue中按順序等待,Looper負責取出並分發給對應的Handler處理。
4. 如何操作
創建Handler時,它與Looper綁定,通常是當前線程的Looper。在非主線程,需先開啟Looper並綁定到Handler,確保消息能正確傳遞。消息的發送、Looper的輪詢和Handler的回調構成了整個工作流程。
5. 關鍵類理解
包括Message、Handler和Looper,Message用於封裝任務數據,Handler負責處理消息,Looper則負責消息隊列的管理。創建Handler時,確保在主線程,否則需手動設置Looper。
5. 能講講Android的Handler機制嗎
Android的Handler機制是通俗講為了互相發消息,一般是子線程給主線程發消息完成相應操作。
安卓中最常見的操作是子線程操作完事後得到數據想更新UI,安卓有規定不允許在子線程中刷新UI,所以Handler出現了。
使用和理解大致步驟。
創建全局Handler對象handler,然後在主線程中初始化它(一般在oncreate中),把它的handmessage裡面的方法重寫,這個方法是收到子線程發給它的消息後執行的邏輯。
在子線程中獲取數據,調用handler.sendmessage,把要發的消息放在message中。message會添加到Messagequue(消息隊列中,handler創建就帶的)。
3.對象handler被創建和初始化的時候,系統自動會啟動Handler.looper,也就是一個消息輪詢器,它不斷的去查看有沒有消息進入到Messagequue(消息隊列中),有就取出交給handler的handmessage去處理。//這段邏輯是系統自動執行,理解就行。*純手打,不騙人~~~