先前有寫過簡單的範例, 來示範怎麼使用Thread&Handler
請參考如何使用Thread和Handler
這篇想討論Handler的兩個方法, post跟sendMessage的差異。
從如何使用Thread和Handler這篇知道sendMessage的使用方法,
會先開啟一隻Thread去執行我們複雜的計算,
之後透過Handler的物件去發送一個Message物件,
用來通知UI Thread更新畫面。
而Handler的post方法, 我想知道跟sendMessage差別在哪裡,
因此作了以下的實驗。
private Handler mHandler = new Handler(){
public void handleMessage(Message msg){
switch(msg.what){
case 0:
Log.e("HandlerThreadID", Long.toString(Thread.currentThread().getId()));
Log.e("HandlerThreadName", Thread.currentThread().getName());
break;
}
}
};
private Thread mThread = new Thread(new Runnable() {
public void run() {
Log.e("ThreadID", Long.toString(Thread.currentThread().getId()));
Log.e("ThreadName", Thread.currentThread().getName());
Message msg = new Message();
msg.what = 0;
handler.sendMessage(msg);
}
});
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mThread.start();
Log.e("ActivityThreadID",
Long.toString(Thread.currentThread().getId()));
Log.e("ActivityThreadName",Thread.currentThread().getName());
}
印出來的結果是這樣
ThreadID: 78
ThreadName: Thread-78
ActivityThreadID: 1
ActivityThreadName: main
HandlerThreadID: 1
HandlerThreadName: main
由上面結果可以知道, 這樣的做法會產生一支新的Thread來幫我們執行程式。
接著是另外一種Handler.post的方法, 這種作法野蠻常見的,
將實作好的Runnable物件丟進post讓Handler去執行。
private class MyHandler extends Handler{
public MyHandler(){
Log.e("HandlerThreadID", Long.toString(Thread.currentThread().getId()));
Log.e("HandlerThreadName",Thread.currentThread().getName());
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyHandler mHandler2 = new MyHandler();
mHandler2.post(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
Log.e("RunnableThreadID", Long.toString(Thread.currentThread().getId()));
Log.e("RunnableThreadName",Thread.currentThread().getName());
}
});
//mThread.start();
Log.e("ActivityThreadID", Long.toString(Thread.currentThread().getId()));
Log.e("ActivityThreadName",Thread.currentThread().getName());
}
印出來的結果是
HandlerThreadID: 1
HandlerThreadName: main
ActivityThreadID: 1
ActivityThreadName: main
RunnableThreadID: 1
RunnableThreadName: main
從上面結果來看, 並沒有產生新的Thread來幫我們執行程式,
因此產生幾種猜測
1. sendMessage在之前, 我們有開一支新的Thread並且start(), 因此會產生新的Thread
2. post並不會產生新的Thread, sendMessage會
3. 因為post傳入的是Runnable, 因此不會產生新的Thread
先來驗證第三種說法
private class MyThread extends Thread{
public MyThread(Runnable r){
super(r);
Log.e("ThreadID",Long.toString(Thread.currentThread().getId()));
Log.e("ThreadName",Thread.currentThread().getName());
}
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyHandler mHandler2 = new MyHandler();
mHandler2.post(new MyThread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
Log.e("RunnableThreadID", Long.toString(Thread.currentThread().getId()));
Log.e("RunnableThreadName",Thread.currentThread().getName());
}
}));
//mThread.start();
Log.e("ActivityThreadID", Long.toString(Thread.currentThread().getId()));
Log.e("ActivityThreadName",Thread.currentThread().getName());
}
結果是
HandlerThreadID: 1
HandlerThreadName: main
ThreadID: 1
ThreadName: main
ActivityThreadID: 1
ActivityThreadName: main
RunnableThreadID: 1
RunnableThreadName: main
由結論得知, 即使傳入一支Thread, Handler也不會幫我們啟動它,
因此第三種猜測不攻自破。
接下來驗證第二種猜測, 怎麼驗證呢?
最簡單的就是爬Handler source code,
找到以下的網站可以看見Android的source code,
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.1_r2/android/os/Handler.java#Handler.Callback
爬的過程就不細說了, 有興趣的人可以去爬看看XD
流程是我們傳入一個Runnable的物件進去, 最後會被丟進Message物件的Runnable變數,
而這個Message會被送往MessageQueue裡面等待被處理,
當輪到這個Message物件被處理的時候, 就會被Looper這個東西來啟動,
最後我們傳進去Runnable物件就會被run起來。
因此從這邊可以得到一個資訊, 並沒有產生任何新的Thread,
而順便去看一下sendMessage的source code, 發現流程也是相同的,
所以第二種猜測也是不正確的。
我在網路上看到很多說法是第二種,
post並不會產生新的Thread, sendMessage會
這是錯誤的!!!!
所以結論是
除非我們自己寫一個Thread並且start它,
否則sendMessage或者post都不會產生新的Thread。