2012年2月27日 星期一

Android AsyncTask note

Introduction

Andr​​oid應用程式中常會遇到需要耗時執行的時候(下載音樂),因此我們會將這部分的工作安排在背景後面工作,以免造成使用者還須等待下載工作完成後才能繼續執行其他操作,一般作法都會使用Thread、 Handler。
Android為了降低開發上的難度,提供了AsyncTask供開發者方便使用。 AsyncTask就是一個封裝過的後台任務類,稱為"異步任務"。AsyncTask 讓我們可以在UI thread(使用者介面執行緒,也就是你手機應用程式畫面所看到的)中執行非同步工作。它在worker thread中執行需耗時的工作,然後將結果傳回使用介面緒,省掉我們處裡 Thread、 Handler的麻煩。


Application
常見的有上傳下載圖片音樂,當我們在一邊瀏覽音樂目錄,有一邊下載想要音樂時。
解決Intent回傳於onActivityResult方法中無法顯示提醒視窗或等待視窗(如 ProcessDialog等)。

Overview

建立一個內部類繼承AsyncTask 類別,宣告子類別時指定所使用的三個泛型參數的類別,

Params,Progress和Result。

AsyncTask<Params, Progress, Result>,實作時定義參數型態,

Params 啟動任務執行的輸入參數,如HTTP請求的URL。
Progress 後台任務執行的百分比。
Result 後台執行任務最終返回的結果,如String。

例如AsyncTask< Integer , Integer , String >
Params為Integer ; Params為Integer ;  Result 為String
AsyncTask<Integer, Integer, String>
第一個參數對應呼叫execute()和doInBackground()的參數,不故定數目的參數,可以是陣列。
第二個參數對應呼叫publishProgress()和onProgressUpdate()的參數, 不故定數目的參數,可以是陣列 。
第三個參數對應doInBackground()的回傳值和onPostExecute()的呼叫參數。

生命週期:
1. execute() :於UI Tread啟動任務
2. onPreExecute() : 任務開始
3. doInBackground() : 在背景執行緒池,執行主要的背景工作,自動在worker thread中執行。可隨時呼叫 publishProgress() 來執行介面緒的 onProgressUpdate()更新介面進度。doInBackground() 的傳回值會傳給 onPostExecute()。
4. onProgressUpdate() :獲取資料即時在介面上更新
5. onPostExecute() : 任務結束
onPreExecute(), onPostExecute(), 和 onProgressUpdate() 都在介面緒執行(不直接呼叫也不可手動呼叫)。

PS:記得處理工作緒的意外重新啟動,例如使用者旋轉螢幕等。
http://changxianli6121.blog.163.com/blog/static/56392130201042712956597/
http://neurosoft.blogspot.com/2011/11/android-threads-handlers-and-asynctask.html
http://developer.android.com/reference/android/os/AsyncTask.html
http://zjf1428.iteye.com/blog/919066

以下code為一開始跳出等待視窗,等待進度bar完成後,等待視窗便消失!
--------------------------------------------------------------------------------------------------------
public class AsyncTask1Activity extends Activity {
    /** Called when the activity is first created. */

private ProgressBar pBar;

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
   
        pBar = (ProgressBar) findViewById(R.id.progress_bar);
    //AsyncTask.execute()要在主線程調用
    new AsyncLoader().execute(0);
    }

  //AsyncTask
  // 設置三種參數分別是<Integer,Integer,String> ,對應著
  // doInBackground(Params),onProgressUpdate(Progress),onPostExecute(Result)參數
  class AsyncLoader extends AsyncTask<Integer, Integer, String>{


private ProgressDialog pdg = null;
@Override
protected String doInBackground(Integer...integers) {
// TODO Auto-generated method stub
          Log.d("TAG", "doInBackground()");
     
          for (int i=integers[0]; i <= 100;i+=10) {
              publishProgress(i);
              try {
                  Thread.sleep(500);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
          return null;
}

@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
//任務執行前
Log.d("TAG", "onPreExecute");
pdg = ProgressDialog.show(AsyncTask1Activity.this,"please wait...","Android accessing",true);
}


@Override
protected void onProgressUpdate(Integer... progress) {
// TODO Auto-generated method stub
super.onProgressUpdate(progress);
//任務執行中UI上進度更新
Log.d("TAG", "onProgressUpdate");
pBar.setProgress(progress[0]);
}

@Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
//任務執行後
Log.d("TAG", "onPostExecute");
pdg.dismiss();
}

@Override
protected void onCancelled() {
// TODO Auto-generated method stub
super.onCancelled();
Log.d("TAG", "onCancelled");
}
  }
}







沒有留言:

張貼留言