在工作線程中使用Handler
在UI線程中已經有了Looper,但是在工作線程中要自己實作Looper:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop(); //不能在這個後面添加代碼,程式是無法運作到這行之後的
}
}
在建立Handler之前,為該線程準備好一個Looper(Looper.prepare),然後讓這個Looper跑起來(Looper.loop),抽取Message,這樣,Handler才能正常工作。
不是所有的Handler都能更新UI
Handler處理消息總是在建立Handler的線程裡運作。而我們的消息進行中,不乏更新UI的操作,不正确的線程直接更新UI将引發異常。是以,需要時刻關心Handler在哪個線程裡建立的。如何更新UI才能不出異常呢?SDK告訴我們,有以下4種方式可以從其它線程通路UI線程(也即線程間通信):
· Activity.runOnUiThread(Runnable)
· View.post(Runnable)
· View.postDelayed(Runnable, long)
· 在UI線程中建立的Handler
其中,重點說一下的是View.post(Runnable)方法。在post(Runnable action)方法裡,View獲得目前線程(即UI線程)的Handler,然後将action對象post到Handler裡。在Handler裡,它将傳遞過來的action對象包裝成一個Message(Message的callback為action),然後将其投入UI線程的消息循環中。在 Handler再次處理該Message時,有一條分支(未解釋的那條)就是為它所設,直接調用runnable的run方法。而此時,已經路由到UI線程裡,是以,我們可以毫無顧慮的來更新UI。
幾點小結
· Handler的處理過程運作在建立Handler的線程裡
· 一個Looper對應一個MessageQueue,一個線程對應一個Looper,一個Looper可以對應多個Handler
· 不确定目前線程時,更新UI時盡量調用View.post方法
· handler應該由處理消息的線程建立。
· handler與建立它的線程相關聯,而且也隻與建立它的線程相關聯。handler運作在建立它的線程中,是以,如果在handler中進行耗時的操作,會阻塞建立它的線程。
· Android的線程分為有消息循環的線程和沒有消息循環的線程,有消息循環的線程一般都會有一個Looper。主線程(UI線程)就是一個消息循環的線程。
· Looper.myLooper(); //獲得目前的Looper
Looper.getMainLooper () //獲得UI線程的Lopper
· Handle的初始化函數(構造函數),如果沒有參數,那麼他就預設使用的是目前的Looper,如果有Looper參數,就是用對應的線程的Looper。
· 如果一個線程中調用Looper.prepare(),那麼系統就會自動的為該線程建立一個消息隊列,然後調用 Looper.loop();之後就進入了消息循環,這個之後就可以發消息、取消息、和處理消息。
Android提供了一個封裝好的帶有looper的線程類,即為HandlerThread,具體可參見下面的代碼:
public class HandlerThreadActivity extends Activity {
private static final String TAG = "HandlerThreadActivity";
private HandlerThread mHandlerThread;
private MyHandler mMyHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
TextView text = new TextView(this);
text.setText("HandlerThreadActivity");
setContentView(text);
Log.d(TAG, "The main thread id = " + Thread.currentThread().getId());
//生成一個HandlerThread對象,實作了使用Looper來處理消息隊列的功能,
//這個類由Android應用程式架構提供
mHandlerThread = new HandlerThread("handler_thread");
//在使用HandlerThread的getLooper()方法之前,必須先調用該類的start();
mHandlerThread.start();
//即這個Handler是運作在mHandlerThread這個線程中
mMyHandler = new MyHandler(mHandlerThread.getLooper());
mMyHandler.sendEmptyMessage(1);
}
private class MyHandler extends Handler {
public MyHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
Log.d(TAG, "MyHandler-->handleMessage-->thread id = " + Thread.currentThread().getId());
super.handleMessage(msg);
}
}
}