Handler機制的簡單原理
因爲android UI界面不是線程安全的,不允許子線程更新主UI線程,爲了達到主界面的更新操作,此時便有了Handler對象.
Android UI操作並不是線程安全的並且這些操作必須在UI線程中執行。Android利用Handler來實現UI線程的更新的。
Handler是Android中的消息發送器,其在哪個Activity中創建就屬於且緊緊屬於該Activity。還可以說其在哪個線程中new的,就是那個線程的Handler。
Handler的定義: 主要接受子線程發送的數據, 並用此數據配合主線程更新UI.
在UI線程:
handler對象首先在主界面中進行聲明,並覆蓋其中的handleMessage(msg)方法。該方法用來接收子線程傳遞來的Message對象。
在子線程:
子線程啓動後,首先創建Message對象。然後將待發送的數據放入Message對象中,並使用handler的sendMessage(msg)來發送msg對象,發送成功夠,handleMessage(msg)拿到msg對象,並用這個msg對象裏面的數據 來在主線程中更新手機界面。
Handler特點 :
handler可以分發Message對象和Runnable對象到主線程中,每個Handler實例,都會綁定到創建他的線程中(一般是位於主線程),
它有兩個作用:
(1)安排消息或Runnable在某個主線程中某個地方執行
(2)安排一個動作在不同的線程中執行
Handler中分發消息的一些方法 :
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
sendMessage類方法,允許你安排一個帶數據的Message對象到隊列中,等待更新.
比如看看一般歡迎界面的實現方法:
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
public class WelcomeScreen extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.welcome_screen);
Handler handler = new Handler();
handler.postDelayed(new Loading(), 2000);//2s後執行Loading線程, 跳轉到MainActivity
}
class Loading implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
startActivity(new Intent(WelcomeScreen.this,MainActivity.class));
WelcomeScreen.this.finish();
}
}
}
補充別人總結的:
1、向哪個Handler發送消息,就必須在哪個handler裏面接收;
2、直接使用JAVA的 Thread是無法更新Android UI的,因爲Android View在設計的時線程是不完全的,不過Android提供了幾種供開發者在線程中更新UI的方法,如下:
runOnUiThread( Runnable )
post( Runnable )
postDelayed( Runnable, long )
3、直接使用hanlder.post等方法是在當前主線程裏面做操作,而不是另外新建線程,建議使用Thread線程直接新建另外一個線程或者使用HandlerThread類也可以。(這句話的意思是ui線程是主線程,把一些耗時的操作放入其他線程做,主線程僅僅更新視圖)
4、記住消息隊列的先進先出原則。
需要注意的:
一. Handler與Thread的區別。
Handler與調用者處於同一線程,如果Handler裏面做耗時的動作,調用者線程會阻塞。Android UI操作不是線程安全的,並且這些操作必須在UI線程中執行。Android提供了幾種基本的可以在其他線程中處理UI操作的方案,包括Activity的runOnUiThread(Runnable),View的post以及1.5版本的工具類AsyncTask等方案都採用了Handler,Handler的post對線程的處理也不是真正start一個新的線程,而是直接調用了線程的run方法,這正是google煞費苦心搞一套Handler的用意。
二.Handler對於Message的處理不是併發的。
一個Looper只有處理完一條Message纔會讀取下一條,所以消息的處理是阻塞形式的。但是如果用不同的Looper則能達到併發的目的。Service中,onStart的執行也是阻塞的。如果一個startService在onStart執行完成之前,再次條用startService也會阻塞。如果希望能儘快的執行onStart則可以在onStart中使用handler,因爲Message的send是非阻塞的。如果要是不同消息的處理也是併發的,則可以用不同的Looper實例化Handler。
三. 資源回收
向Handler對象發送類似new Message ()形式的空Message可以達到清空Message的目的,這種做法與getLooper().quit()的做法是一樣的。如果利用的資源較多,應及時清理。
Android中實現view的更新有第二種方法:
Android中實現view的更新有兩組方法,一組是invalidate,另一組是postInvalidate,其中前者是在UI線程自身中使用,而後者在非UI線程中使用。
Android提供了Invalidate方法實現界面刷新,但是Invalidate不能直接在線程中調用,因爲他是違背了單線程模型:Android UI操作並不是線程安全的,並且這些操作必須在UI線程中調用。
Android程序中可以使用的界面刷新方法有兩種,分別是利用Handler和利用postInvalidate()來實現在線程中刷新界面。
1,利用invalidate()刷新界面
實例化一個Handler對象,並重寫handleMessage方法調用invalidate()實現界面刷新;而在線程中通過sendMessage發送界面更新消息。
2,使用postInvalidate()刷新界面
使用postInvalidate則比較簡單,不需要handler,直接在線程中調用postInvalidate即可。
程序如下: /**
* 1 利用invalidate()刷新界面
* 實例化一個Handler對象,並重寫handleMessage方法.
* 調用invalidate()實現界面刷新;
* 而在線程中通過sendMessage發送界面更新消息。
*
*/
// 在onCreate()中開啓線程
new Thread(new GameThread()).start();
// 實例化一個handler
Handler myHandler = new Handler() {
// 接收到消息後處理
public void handleMessage(Message msg) {
switch (msg.what) {
case Activity01.REFRESH: mGameView.invalidate(); // 刷新界面
break;
}
super.handleMessage(msg);
}
};
}
class GameThread implements Runnable {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
Message message = new Message();
message.what = Activity01.REFRESH;
// 發送消息
Activity01.this.myHandler.sendMessage(message);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
//2,使用postInvalidate()刷新界面
// 使用postInvalidate則比較簡單,不需要handler,直接在線程中調用postInvalidate即可。
class GameThread2 implements Runnable {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 使用postInvalidate可以直接在線程中更新界面
mGameView.postInvalidate();
}
}
}