一、AsyncTask介紹
Android提供了幾種在其他線程中訪問UI線程的方法。
Activity.runOnUiThread( Runnable ) View.post( Runnable ) View.postDelayed( Runnable, long ) Hanlder
這些類或方法同樣會使你的代碼很復雜很難理解。然而當你需要實現一些很復雜的操作並需要頻繁地更新UI時這會變得更糟糕。
為了解決這個問題,Android 1.5提供了一個工具類:AsyncTask,它使創建需要與用戶界面交互的長時間運行的任務變得更簡單。不需要借助線程和Handler即可實現。
AsyncTask是抽象類.AsyncTask定義了三種泛型類型 Params,Progress和Result。
◆Params 啟動任務執行的輸入參數,比如HTTP請求的URL。
◆Progress 后台任務執行的百分比。
◆Result 后台執行任務最終返回的結果,比如String。
AsyncTask的執行分為四個步驟,每一步都對應一個回調方法,這些方法不應該由應用程序調用,開發者需要做的就是實現這些方法。
子類化AsyncTask
實現AsyncTask中定義的下面一個或幾個方法
onPreExecute()
該方法將在執行實際的后台操作前被UI thread調用。可以在該方法中做一些准備工作,如在界面上顯示一個進度條。
doInBackground(Params...)
將在onPreExecute 方法執行后馬上執行,該方法運行在后台線程中。這里將主要負責執行那些很耗時的后台計算工作。可以調用 publishProgress方法來更新實時的任務進度。該方法是抽象方法,子類必須實現。
onProgressUpdate(Progress...)
在publishProgress方法被調用后,UI thread將調用這個方法從而在界面上展示任務的進展情況,例如通過一個進度條進行展示。
onPostExecute(Result)
在doInBackground 執行完成后,onPostExecute 方法將被UI thread調用,后台的計算結果將通過該方法傳遞到UI thread.
為了正確的使用AsyncTask類,以下是幾條必須遵守的准則:
1) Task的實例必須在UI thread中創建
2) execute方法必須在UI thread中調用
3) 不要手動的調用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)這幾個方法
4) 該task只能被執行一次,否則多次調用時將會出現異常
針對主線程和AsyncTask子線程的調用關系如下圖:

1>主線程調用AsynTask子類實例的execute()方法后,首先會調用onPreExecute()方法。onPreExecute()在主線程中運行,可以用來寫一些開始提示代碼。
2>之后啟動新線程,調用doInBackground()方法,進行異步數據處理。
3>處理完畢之后異步線程結束,在主線程中調用onPostExecute()方法。onPostExecute()可以進行一些結束提示處理。
補充:在doInBackground()方法異步處理的時候,如果希望通知主線程一些數據(如:處理進度)。這時,可以調用publishProgress()方法。這時,主線程會調用AsynTask子類的onProgressUpdate()方法進行處理。
各個函數間數據的傳遞
通過上面的調用關系,我們就可以大概看出一些數據傳遞關系。如下:
  execute()向doInBackground()傳遞。
  doInBackground()的返回值會傳遞給onPostExecute()。
  publishProgress()向progressUpdate()傳遞。
 
要點:為了調用關系明確及安全,AsynTask類在繼承時要傳入3個泛型。第一個泛型對應execute()向doInBackground()的傳遞類型。第二個泛型對應doInBackground()的返回類型和傳遞給onPostExecute()的類型。第三個泛型對應publishProgress()向progressUpdate()傳遞的類型。
傳遞的數據都是對應類型的數組,數組都是可變長的哦。可以根據具體情況使用。
二、圖片異步下載舉例說明
1.首先定義一個簡單布局:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:paddingBottom="@dimen/activity_vertical_margin" 6 android:paddingLeft="@dimen/activity_horizontal_margin" 7 android:paddingRight="@dimen/activity_horizontal_margin" 8 android:paddingTop="@dimen/activity_vertical_margin" 9 tools:context=".MainActivity" > 10 11 <Button 12 android:id="@+id/btndownload" 13 android:layout_width="wrap_content" 14 android:layout_height="wrap_content" 15 android:layout_alignParentBottom="true" 16 android:layout_centerHorizontal="true" 17 android:text="DOWNLOAD" /> 18 19 <EditText 20 android:id="@+id/texturl" 21 android:layout_width="wrap_content" 22 android:layout_height="wrap_content" 23 android:layout_above="@+id/btndownload" 24 android:layout_centerHorizontal="true" 25 android:ems="10" > 26 27 <requestFocus /> 28 </EditText> 29 30 <ImageView 31 android:id="@+id/imageView1" 32 android:layout_width="wrap_content" 33 android:layout_height="wrap_content" 34 android:layout_alignParentTop="true" 35 android:layout_centerHorizontal="true" 36 android:layout_above="@id/texturl" 37 android:src="@drawable/ic_launcher" /> 38 39 </RelativeLayout>
2.別忘了加上網絡訪問權限
1 <uses-sdk 2 android:minSdkVersion="8" 3 android:targetSdkVersion="18" /> 4 <uses-permission android:name="android.permission.INTERNET"/>
3.進入到MainActivity進入主要代碼編寫
1 package com.example.android_asynctask_download; 2 3 import java.io.ByteArrayOutputStream; 4 import java.io.IOException; 5 import java.io.InputStream; 6 7 import org.apache.http.HttpResponse; 8 import org.apache.http.HttpStatus; 9 import org.apache.http.client.HttpClient; 10 import org.apache.http.client.methods.HttpGet; 11 import org.apache.http.impl.client.DefaultHttpClient; 12 13 import android.os.AsyncTask; 14 import android.os.Bundle; 15 import android.app.Activity; 16 import android.app.ProgressDialog; 17 import android.graphics.Bitmap; 18 import android.graphics.BitmapFactory; 19 import android.view.Menu; 20 import android.view.View; 21 import android.view.View.OnClickListener; 22 import android.widget.Button; 23 import android.widget.EditText; 24 import android.widget.ImageView; 25 26 public class MainActivity extends Activity { 27 28 private Button button; 29 private ImageView imageView; 30 private EditText texturl; 31 private String pic_pathString = "http://b.hiphotos.baidu.com/image/h%3D1200%3Bcrop%3D0%2C0%2C1920%2C1200/sign=165d5bcf9f16fdfac76cc2ec84bfb737/bf096b63f6246b60bd811290e9f81a4c500fa243.jpg"; 32 private ProgressDialog progressDialog; 33 34 @Override 35 protected void onCreate(Bundle savedInstanceState) { 36 super.onCreate(savedInstanceState); 37 setContentView(R.layout.activity_main); 38 39 button = (Button) this.findViewById(R.id.btndownload); 40 imageView = (ImageView) this.findViewById(R.id.imageView1); 41 texturl = (EditText) this.findViewById(R.id.texturl); 42 texturl.setText(pic_pathString); 43 progressDialog = new ProgressDialog(this); 44 progressDialog.setTitle("提示信息"); 45 progressDialog.setMessage("正在下載,請稍后..."); 46 progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); 47 button.setOnClickListener(new OnClickListener() { 48 49 @Override 50 public void onClick(View v) { 51 // TODO Auto-generated method stub 52 pic_pathString = texturl.getText().toString(); 53 new mytask().execute(pic_pathString); 54 } 55 }); 56 57 } 58 59 public class mytask extends AsyncTask<String, Integer, Bitmap> { 60 @Override 61 protected void onPreExecute() { 62 // TODO Auto-generated method stub 63 // super.onPreExecute(); 64 progressDialog.show(); 65 } 66 67 @Override 68 protected Bitmap doInBackground(String... params) { 69 // // TODO Auto-generated method stub 70 // Bitmap bitmap = null; 71 // HttpClient httpClient = new DefaultHttpClient(); 72 // HttpGet httpGet = new HttpGet(params[0]); 73 // try { 74 // HttpResponse httpResponse = httpClient.execute(httpGet); 75 // if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { 76 // byte[] data = EntityUtils.toByteArray(httpResponse 77 // .getEntity()); 78 // bitmap = BitmapFactory 79 // .decodeByteArray(data, 0, data.length); 80 // } 81 // } catch (ClientProtocolException e) { 82 // // TODO Auto-generated catch block 83 // e.printStackTrace(); 84 // } catch (IOException e) { 85 // // TODO Auto-generated catch block 86 // e.printStackTrace(); 87 // } 88 // 89 // return bitmap; 90 91 //完成對圖片的下載和進度數值的更新 92 Bitmap bitmap = null; 93 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 94 InputStream inputStream = null; 95 try { 96 HttpClient httpClient = new DefaultHttpClient(); 97 HttpGet httpGet = new HttpGet(params[0]); 98 HttpResponse httpResponse = httpClient.execute(httpGet); 99 if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { 100 inputStream = httpResponse.getEntity().getContent(); 101 //先要獲得文件的總長度 102 long file_length = httpResponse.getEntity().getContentLength(); 103 int len = 0; 104 byte[] data = new byte[128]; 105 int total_length = 0; 106 while ((len = inputStream.read(data)) != -1) { 107 total_length+=len; 108 int value = (int)((total_length/(float)file_length)*100); 109 publishProgress(value); 110 outputStream.write(data, 0, data.length); 111 } 112 byte[] result = outputStream.toByteArray(); 113 bitmap = BitmapFactory.decodeByteArray(result, 0, result.length); 114 } 115 } catch (Exception e) { 116 // TODO: handle exception 117 }finally{ 118 if(inputStream != null) 119 { 120 try { 121 inputStream.close(); 122 } catch (IOException e) { 123 // TODO Auto-generated catch block 124 e.printStackTrace(); 125 } 126 } 127 } 128 129 return bitmap; 130 } 131 132 @Override 133 protected void onProgressUpdate(Integer... values) { 134 // TODO Auto-generated method stub 135 //super.onProgressUpdate(values); 136 progressDialog.setProgress(values[0]); 137 } 138 139 @Override 140 protected void onPostExecute(Bitmap result) { 141 // TODO Auto-generated method stub 142 // super.onPostExecute(result); 143 progressDialog.dismiss(); 144 imageView.setImageBitmap(result); 145 } 146 147 } 148 149 @Override 150 public boolean onCreateOptionsMenu(Menu menu) { 151 // Inflate the menu; this adds items to the action bar if it is present. 152 getMenuInflater().inflate(R.menu.main, menu); 153 return true; 154 } 155 156 }
在手機上運行的樣子:

謝謝耐心閱讀,希望對您有些幫助。
