很多情況下,我們會提供一個UI (Activity)給User操作,但是一些比較耗時的計算可能用另一個Thread執行。重點來了,如果只是在Activity中使用 Handler,然後post一個有 implements Runnable的物件去執行耗時的工作,那是行不通的。程式如下:
public class MainThread extends Activity {
private Handler handler = new Handler();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler.post(new MyRunnable());
...
...
...
}
private class MyRunnable implements Runnable {
//耗時的工作
}
}
這樣的程式寫法,依然有可能讓UI有停頓的感覺,甚至是ANR的錯誤發生。因為上述寫法的MyRunnable其實和MainThread都是在同一條thread裡面工作,並沒有真正拉出一條新的thread。為了解決這個問題可以利用Handler、HandlerThread來達成。
下面程式順便呈現如何把資料由原本的main thread 丟到 thread。
程式碼如下:
public class MainThread extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d("TestHandlerThread","The MainThread is :"+Thread.currentThread().getId());
//"HandlerThread"隨便你取,後面參數決定Thread的優先權高低,
//因為要背景作業,所以不用選太高
Log.d("TestHandlerThread","new HandlerThread()");
HandlerThread myHandlerThread = new HandlerThread("HandlerThread",Process.THREAD_PRIORITY_BACKGROUND);
Log.d("TestHandlerThread","before start()");
myHandlerThread.start();
Log.d("TestHandlerThread","before getLooper()");
MyHandler myHandler = new MyHandler(myHandlerThread.getLooper());
Log.d("TestHandlerThread","obtainMessage()");
Message myMessage = myHandler.obtainMessage();
//Bundle的物件就是用來傳遞用的
Bundle myBundle = new Bundle();
myBundle.putString("name", "Gill");
myMessage.setData(myBundle);
Log.d("TestHandlerThread","before sendToTarget()");
myMessage.sendToTarget();
}
class MyHandler extends Handler{
public MyHandler(){
}
public MyHandler(Looper looper){
super(looper);
Log.d("TestHandlerThread","MyHandler/MyHandler(Looper looper)");
}
@Override
public void handleMessage(Message msg) {
//這裡可以在接收到所需的資料後,再進行一些比較耗時的工作
Log.d("TestHandlerThread","MyHandler/handleMessage");
Log.d("TestHandlerThread","The MyHandler is :"+Thread.currentThread().getId());
Bundle myBundle = msg.getData();
String myName = myBundle.getString("name");
Toast.makeText(MainThread.this, myName, Toast.LENGTH_LONG).show();
}
}
}
執行結果如下:
附上程式執行的Log檔:
D/TestHandlerThread( 310): The MainThread is :1
D/TestHandlerThread( 310): new HandlerThread()
D/TestHandlerThread( 310): before start()
D/TestHandlerThread( 310): before getLooper()
D/TestHandlerThread( 310): MyHandler/MyHandler(Looper looper)
D/TestHandlerThread( 310): obtainMessage()
D/TestHandlerThread( 310): before sendToTarget()
D/TestHandlerThread( 310): MyHandler/handleMessage
D/TestHandlerThread( 310): The MyHandler is :8
從Log檔可以發現,兩條Thread確實是分開的。另外在呼叫了sendToTarget()之後,就會去handleMessage()進行處理。
public class MainThread extends Activity {
private Handler handler = new Handler();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler.post(new MyRunnable());
...
...
...
}
private class MyRunnable implements Runnable {
//耗時的工作
}
}
這樣的程式寫法,依然有可能讓UI有停頓的感覺,甚至是ANR的錯誤發生。因為上述寫法的MyRunnable其實和MainThread都是在同一條thread裡面工作,並沒有真正拉出一條新的thread。為了解決這個問題可以利用Handler、HandlerThread來達成。
下面程式順便呈現如何把資料由原本的main thread 丟到 thread。
程式碼如下:
public class MainThread extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d("TestHandlerThread","The MainThread is :"+Thread.currentThread().getId());
//"HandlerThread"隨便你取,後面參數決定Thread的優先權高低,
//因為要背景作業,所以不用選太高
Log.d("TestHandlerThread","new HandlerThread()");
HandlerThread myHandlerThread = new HandlerThread("HandlerThread",Process.THREAD_PRIORITY_BACKGROUND);
Log.d("TestHandlerThread","before start()");
myHandlerThread.start();
Log.d("TestHandlerThread","before getLooper()");
MyHandler myHandler = new MyHandler(myHandlerThread.getLooper());
Log.d("TestHandlerThread","obtainMessage()");
Message myMessage = myHandler.obtainMessage();
//Bundle的物件就是用來傳遞用的
Bundle myBundle = new Bundle();
myBundle.putString("name", "Gill");
myMessage.setData(myBundle);
Log.d("TestHandlerThread","before sendToTarget()");
myMessage.sendToTarget();
}
class MyHandler extends Handler{
public MyHandler(){
}
public MyHandler(Looper looper){
super(looper);
Log.d("TestHandlerThread","MyHandler/MyHandler(Looper looper)");
}
@Override
public void handleMessage(Message msg) {
//這裡可以在接收到所需的資料後,再進行一些比較耗時的工作
Log.d("TestHandlerThread","MyHandler/handleMessage");
Log.d("TestHandlerThread","The MyHandler is :"+Thread.currentThread().getId());
Bundle myBundle = msg.getData();
String myName = myBundle.getString("name");
Toast.makeText(MainThread.this, myName, Toast.LENGTH_LONG).show();
}
}
}
執行結果如下:
附上程式執行的Log檔:
D/TestHandlerThread( 310): The MainThread is :1
D/TestHandlerThread( 310): new HandlerThread()
D/TestHandlerThread( 310): before start()
D/TestHandlerThread( 310): before getLooper()
D/TestHandlerThread( 310): MyHandler/MyHandler(Looper looper)
D/TestHandlerThread( 310): obtainMessage()
D/TestHandlerThread( 310): before sendToTarget()
D/TestHandlerThread( 310): MyHandler/handleMessage
D/TestHandlerThread( 310): The MyHandler is :8
從Log檔可以發現,兩條Thread確實是分開的。另外在呼叫了sendToTarget()之後,就會去handleMessage()進行處理。
沒有留言:
張貼留言