2011年11月30日

Android: AsyncTask 非同步任務

AsyncTask 讓我們可在UI thread中執行非同步工作。它在worker thread中執行需長時間的作業,然後將結果傳回使用介面緒,省掉我們親自處理Thread或Handlers的麻煩。
使用方法很簡單,從AsyncTask 類別衍生子類別,實作doInBackground()運行在背景執行緒池,執行主要的背景工作。實作onPostExecute()運行在介面緒,當執行結束時傳遞結果並更新介面。在介面緒中呼叫此子類別的 execute() 來開始執行。
  • 宣告子類別時指定所使用的三個泛型參數的類別,例如AsyncTask<String, Long, String>其中第一個參數對應呼叫execute()和doInBackground()的參數,為不定數目的參數。第二個參數對應呼叫publishProgress()和onProgressUpdate()的參數,也是不定數目的參數。第三個參數對應doInBackground()的回傳值和onPostExecute()的呼叫參數。
  • doInBackground() 自動在worker thread中執行
  • onPreExecute(), onPostExecute(), 和 onProgressUpdate() 都在介面緒執行(不直接呼叫)。
  • doInBackground() 的傳回值會傳給 onPostExecute()
  • 我們隨時可在doInBackground() 中呼叫 publishProgress() 來執行介面緒的 onProgressUpdate()更新進度
  • 記得處理工作緒的意外重新啟動,例如使用者旋轉螢幕等。
private class downloadTask extends AsyncTask<String, Long, String> {
 private long totalGetBytes=0;
 public downloadTask(Context context) {
    //啟始進度顯示物件
    //....省略
    //例如 msg為Textview,pdialog為progressDialog
    //不一定要在這裡作
 }
 @Override
 protected String doInBackground(String... zfnames) {
   try {
        String ret = "OK";
        for (String zfn : zfnames)
             unzipFile(zfn);//請參閱相關文章unZip
        return ret;
   } catch (Exception e) {
       e.printStackTrace();
   }
   return null;
 }
 @Override
 protected void onCancelled() {
   super.onCancelled();
 }
 @Override
 protected void onPostExecute(String result) {
   msg.setText(result);
   pdialog.dismiss();
 }
 @Override
 protected void onPreExecute() {
   msg.setText("Download begin...");
   totalGetBytes= 0 ;
 }
 @Override
 protected void onProgressUpdate(Long... idxs) {
   //更新進度顯示
   msg.setText("Get Bytes " + idxs[0] + " / " + idx[1]+" bytes");
   pdialog.setProgress((int)((idx[0]/(float)idx[1])*100));
 }
 private int unzipFile(String ZipName) {
    //...
    //計算到目前為止所接收的位元數 totalGetBytes
    publishProgress(totalGetBytes, targetBytes);
    //...
 }
}       
private void doDownload(String[] urls) {
     downloadTask task = new downloadTask(this);
     task.execute(urls);
}

沒有留言: