![]() |
| Fig. 1 ANR Dialog |
為了避免上述的狀況,過於花時的運算和事件等待應避免在UI 執行緒(Activity裡的Main Thread)執行,換句話說可以透過建立額外的Non UI 執行緒來處理,不過Android不允許Non UI 執行緒 (即UI 執行緒下的子執行緒)直接更新UI 執行緒的畫面,所以Non UI 執行緒必須得將自己的資料回傳給UI 執行緒由它負責處理,在這篇文章介紹一個簡單的方法,使用 - runOnUiThread。 runOnUiThread(Runnable action)是Activity Class裡的一個方法 (Method),當Non UI 執行緒呼叫此方法時,會將引數action回傳到UI 執行緒的Event Queue裡等待被執行,所以可以根據實際的設計需求實作特定的action,將Non UI 執行緒的資料傳遞給UI 執行緒也得以實踐。下面的範例程式碼實作了一個忽略時間誤差的簡單時鐘程式,此範例程式透過Non UI 執行緒取得系統時間後傳給UI 執行緒更新畫面。此範例的UI介面有兩個TextView,第一個TextView顯示"A Message form the Non-UI Threads:",用來提示此APP的功能,第二個msgTextView用來顯示Non UI執行緒傳給UI執行緒的資料。關於程式碼的部份,MainActivity class (APP執行時的UI執行緒)裡宣告了一個繼承Thread class的inner class - NonUIThread (APP執行時UI執行緒下的Non UI執行緒),第64和65行是它的成員物件,nonUIThreadName是Non UI執行緒的名字,用來識別是哪一個執行緒,第67到71行的default constructor設定"Unknown Non-UI Thread"為預設的名字,或是透過呼叫第73到76行的constructor賦與不同的名字,另一個成員calendar則是用來獲取裝置所設定的系統年分、日期和時間的日曆物件,第79到90行覆寫了Thread class的run方法,run方法會不斷的去呼叫sayHelloToUIThread方法,第83行的sleep方法設定了讓執行緒下次再繼續執行的時間(即1秒),第91到103行是sayHelloToUIThread方法的實做部分,此方法每隔一秒會被呼叫,並透過Calendar.getInstance()擷取出目前的時間,第93到96行將這些資訊轉換成字串(所有的JAVA calss均會繼承Object class,Object class裡有一個toString的方法,所以calendar.get()回傳的時間會靠此方法轉成字串),第97到102行就是本範例要講的重點,inner class - NonUIThread呼叫了MainActivity的runOnUiThread,傳入引數的Runnable物件一樣覆寫了run方法,run方法會呼叫MainActivity裡的receiveMsgFromNonUIThread方法並,傳入的引數toUIStr即為Non UI執行緒想要傳給UI執行緒的資料 ,第59到61行的receiveMsgFromNonUIThread方法實做則是再呼叫msgTextView的setText方法將目前的時間更新到UI執行緒上。MainActivity的onCreate方法建立了UI畫面和一個Non UI執行緒的物件,在onStart方法裡呼叫nonUIThread1.start()讓Non UI執行緒開始執行獲取系統時間並傳回給UI,Fig.2顯示了此範例APP的執行結果。
package com.example.threadcommunicationex1;
import java.util.Calendar;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
public class MainActivity extends ActionBarActivity {
private TextView msgTextView;
private NonUIThread nonUIThread1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getViewComponent();
CreateThread();
}
@Override
protected void onStart(){
super.onStart();
nonUIThread1.start();
}
private void getViewComponent()
{
msgTextView = (TextView) findViewById(R.id.msg);
msgTextView.setText("");
}
private void CreateThread(){
nonUIThread1 = new NonUIThread("Non-UI Thread 1");
}
private void receiveMsgFromNonUIThread(String msg){
msgTextView.setText(msg);
}
class NonUIThread extends Thread{
private String nonUIThreadName;
private Calendar calendar;
NonUIThread(){
nonUIThreadName = "Unknown Non-UI Thread";
//get a default instance of this class for general use
calendar = Calendar.getInstance();
}
NonUIThread(String name){
this();
nonUIThreadName = name;
}
@Override
public void run(){
while(true){
sayHelloToUIThread();
try {
sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void sayHelloToUIThread(){
calendar = Calendar.getInstance();
final String toUIStr = "This is " + nonUIThreadName +
", " + "current time is " + calendar.get(Calendar.HOUR_OF_DAY)
+ ":" + calendar.get(Calendar.MINUTE) + ":" +
calendar.get(Calendar.SECOND) + "\n\n";
runOnUiThread(new Runnable(){
@Override
public void run(){
receiveMsgFromNonUIThread(toUIStr);
}
});
}
}
}
程式執行的畫面如下:
![]() |
| Fig. 2. 程式執行結果 |
對JAVA執行緒不熟的話可以參考此網站的講解:


沒有留言:
張貼留言