2011-10-27

使用 Android 繞圈進度對話窗 ProgressDialog

Android 進度對話窗的主角為 ProgressDialog,有繞圈(Spinner)與百分比(Horizontal)兩種,這邊要用的是較簡單的繞圈。

產生進度對話窗很容易,要關掉比較複雜一點。

一般會需要進度對話窗就是有較費時的工作要處理,但是因為 Android 有五秒鐘的回應限制,所以不能在 main thread 裡直接進行費時的運算,要用 worker thread,也就是另外起一個 thread 來負責費時的運算,但因為是另一個 thread,所以不能像 main thread 一樣可以控制 UI,也就是說,當 worker thread 執行完成時,得透過 Handler 來告訴 main thread,並且視需要傳遞運算結果給 main thread。

所以整個流程如下:
  • main thread 產生進度對話窗
  • main thread 建立 handler
  • main thread 建立 worker thread 進行費時的運算,並將 handler 傳給 worker thread
  • worker thread 完成運算後,透過 handler 讓 main thread 知道
  • main thread 呼叫 handler 的 callback method 來關閉進度對話窗
主要程式有兩隻:main activity 與 worker thread,以及一隻紀錄 thread 的工具程式。

ProgressActivity
public class ProgressActivity extends Activity {

    private static final String TAG = "ProgressActivity";
    private ProgressDialog progressDialog;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Utils.logThread();

        // 建立並顯示進度對話窗
        this.progressDialog = new ProgressDialog(this);
        this.progressDialog.setTitle("執行中");
        this.progressDialog.setMessage("請稍後...");
        this.progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        this.progressDialog.show();

        // 建立 worker thread,並交付由 main thread 建立的 handler
        // 供 worker thread 稍後與 main thread 溝通
        new Thread(new DoSomethingThread(this.handler)).start();
    }

    private Handler handler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            Utils.logThread();
            // main thread 從 main queue 取得 handler 丟進來的 message
            // 再從該 message 取得 handler 物件
            // 最後呼叫 handler 的 callback method - handleMessage 來關閉進度對話窗
            progressDialog.dismiss();
        }
    };
}
DoSomethingThread
public class DoSomethingThread implements Runnable {

 private Handler handler;

 public DoSomethingThread(Handler handler) {
  super();
  this.handler = handler;
 }

 @Override
 public void run() {
  Utils.logThread();
// 停頓五秒鐘後,通知 main thread 關閉進度對話窗
  try {
   Thread.sleep(5000);
  }
  catch (InterruptedException e) {
   e.printStackTrace();
  }
// 丟一個 message 到 main queue 裡,由 main thread 接手處理
  this.handler.sendEmptyMessage(0);
 }
}
Utils
public class Utils {

 private static final String TAG = "Utils";

 public static final void logThread() {
  Thread t = Thread.currentThread();
  Log.d(TAG,
    "<" + t.getName() + ">id: " + t.getId() + ", Priority: "
      + t.getPriority() + ", Group: "
      + t.getThreadGroup().getName());
 }
}
thread 的執行過程可以從 log 看出來:
10-27 12:29:52.747: DEBUG/Utils(643): <main>id: 1, Priority: 5, Group: main
10-27 12:29:52.917: DEBUG/Utils(643): <Thread-10>id: 10, Priority: 5, Group: main
10-27 12:29:57.919: DEBUG/Utils(643): <main>id: 1, Priority: 5, Group: main

再看看 使用 Android 百分比進度對話窗 ProgressDialog

沒有留言:

張貼留言