最近面試一些Android開發的應聘者,除了基本的Activity生命周期等基礎問題以外,我一般還會問如下兩個問題:
(1) Service與Thread有什麼區別?
(2) 在Activity裡new Handler()和在自己創建的Thread中new Handler()有什麼區別?
第一個問題其實是一個偽命令,因為Service是Android四大組件之一,而Thread只是Java提供的一個封裝了線程管理的工具類,無論是Activity還是Service,都可以通過Thread來創建一個工作線程,但是很多新手會搞不清楚它們之間的區別,借此可以試探一下面試者到底有沒有很清楚地理解Android的Service到底是做什麼的。關於這個問題的答案,可以參考我的文章《Android開發實踐:使用Service還是Thread》 見 http://www.linuxidc.com/Linux/2014-12/110162.htm 。
第二個問題,涉及到Android開發必須掌握的知識點:Handler,本文就來從這個問題開始,說說我對Handler的理解。
當Android應用啟動後,系統會默認創建一個主線程(Main thread)。這個主線程啟動後,首先完成UI的繪制,然後會進入一個消息循環(Loop),等待和執行各種來自系統的消息和事件、各種用戶點擊/觸摸事件、其他線程發送的消息事件等等。這是線程工作的一種常見的模式,即進入一種“等待命令”->“執行命令/消息”->“等待命令/消息”的循環。
那麼,其他非UI線程如何與進入了消息循環的主線程交互呢?這就得靠Handler了。
Handler是Android系統為工作線程提供的一種可以與外界交互的接口,通過Handler提供的sendMessage()方法,外界可以發送各種消息事件給工作線程。Handler通過構造函數完成與指定線程的綁定,其構造函數定義如下:
public Handler() {
this(null, false);
}
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
public interface Callback {
public boolean handleMessage(Message msg);
}
其中,Looper就是線程內部負責實現消息循環的對象,普通的Java.Thread線程內部是沒有這樣一個消息循環對象的,Android專門提供了HandlerThread封裝這種帶消息循環機制的線程。Handler通過與線程的Looper對象綁定,來完成與該Thread的綁定。
Callback則是由工作線程內部傳出接收到的消息的回調接口,其他線程通過Handler的sendMessage發送消息給工作線程後,工作線程就會通過Callback將接收到的消息通知給監聽者。
注意:默認情況下,如果new Handler()的時候,沒有傳入某個線程的Looper對象(或傳入null),系統就會默認綁定到創建Handler()對象的線程中。
那麼,現在可以回答第二個問題了,在Activity裡new Handler()和在自己創建的Thread中new Handler()有什麼區別?
答案:
Activiy默認是工作在主線程中的,所以在Activity中new Handler()後,該Handler對象默認綁定了主線程的Looper對象,因此該Handler.sendMessage消息發送給了主線程,而且通過傳入Callback對象得到的handleMessage()回調也是工作在主線程,這就是為什麼可以通過在Activity裡使用如下方式更新UI而不會導致ANR了:
new Handler( new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
UpdateUI();
return false;
}
});
同理,如果在自定義線程中 new Handler(),則默認情況該Handler()綁定了該線程的Looper對象,因此該Handler.sendMessage消息則是發送給了這個線程,而且通過傳入Callback對象得到的handleMessage()回調也是工作在這個線程,因此,這種情況下的handleMessage()函數中就不能進行UI更新操作了,否則會導致ANR了。
到此為止,這個問題算是回答清楚了,但是關於Handler的解釋還不夠盡興,比如線程的Looper到底是怎麼工作的?下一篇文章(http://www.linuxidc.com/Linux/2014-12/110163.htm),我將用Java的Thread類,實現一個類似Looper的消息循環,以便更好地顯示Android的消息循環機制。本文有任何疑問或者不清楚的地方,歡迎留言或者來信[email protected]交流。
最簡單的Ubuntu Touch & Android 雙系統安裝方式 http://www.linuxidc.com/Linux/2014-01/94881.htm
在Nexus上實現Ubuntu和Android 4.4.2 雙啟動 http://www.linuxidc.com/Linux/2014-05/101849.htm
Ubuntu 14.04 配置 Android SDK 開發環境 http://www.linuxidc.com/Linux/2014-05/101039.htm
64位Ubuntu 11.10下Android開發環境的搭建(JDK+Eclipse+ADT+Android SDK詳細) http://www.linuxidc.com/Linux/2013-06/85303.htm
Ubuntu 14.04 x64配置Android 4.4 kitkat編譯環境的方法 http://www.linuxidc.com/Linux/2014-04/101148.htm
Ubuntu 12.10 x64 安裝 Android SDK http://www.linuxidc.com/Linux/2013-03/82005.htm
更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11