前言
本片博客將介紹AsyncTask的使用,之前有介紹過線程和進程。而在AsyncTask中,運行在用戶界面中,執行異步操作,並且把執行結果發布在UI線程上,且也不需要處理線程和Handler。在本篇博客里,將會講解到AsyncTask的基本介紹,以及如何使用,最后會以一個簡單的Demo講解AsyncTask的使用。
AsyncTask
AsyncTask,異步任務,可以簡單進行異步操作,並把執行結果發布到UI主線程。AsyncTask是一個抽象類,它的內部其實也是結合了Thread和Handler來實現異步線程操作,但是它形成了一個通用線程框架,更清晰簡單。AsyncTask應該被用於比較簡短的操作(最多幾秒鍾)。如果需要保持長時間運行的線程,可以使用ThreadPooExecutor或者FutureTask,關於這兩個類的內容,以后再介紹,本片博客主要介紹AsyncTask。
AsyncTask被定義為一個操作,運行在一個后台線程中,其結果被發布在UI線程上。它的異步工作的參數與返回值被泛型的三個參數指定:Params、Progress、Result。AsyncTask將經歷4個步驟:onPreExecute、doInBackground、onProgressUpdate、onPostExecute。下面詳細講解這三個參數與四個步驟:
三個泛型參數:
- Params:被發送到執行任務的參數類型。
- Progress:進度的類型,發送后台的計算進度到UI線程類型。
- Result:異步任務的返回結果類型。
一個異步任務將經歷四個階段:
- onPreExecute():執行在UI線程上調用執行任務之前,一般用於設置任務。
- doInBackground(Params...):主要是用來執行異步任務的耗時操作,可以在這個方法中通過publishProgress()方法發布進度信息,並在執行完成之后,返回執行結果。
- onProgreddUpdate(Progress...):在UI線程上接受doInBackground()傳遞過來的進度信息,並在UI線程上展示進度信息,它執行的時機是不確定的。
- onPostExecute(Result):在UI線程上操作doInBackground()執行的返回值。
上面介紹的四個步驟的示意圖:
AsyncTask取消任務
在程序的任何位置,都可以通過cancel(boolean)方法進行取消任務,當取消任務之后,會改變isCancelled()的返回值,使其返回true。之后會調用onCancelled(Object)方法,替代onPostExecute()得到doInBackground()的返回結果。在運行中,可以經常通過isCancelled()方法查看任務是否被取消。
AsyncTask的使用規則
使用AsyncTask必須遵循以下規則:
- AsyncTask必須聲明在UI線程上。
- AsyncTask必須在UI線程上實例化。
- 必須通過execute()方法執行任務。
- 不可以直接調用onPreExecute()、onPostExecute(Resut)、doInBackground(Params...)、onProgressUpdate(Progress...)方法。
- 可以設置任務只執行一次,如果企圖再次執行會報錯。
示例
一個簡單的示例,通過AsyncTask下載一個網絡上的圖片,下載的時候展示一個等待框,並顯示在一個ImageView中。
實現代碼:
1 package com.bgxt.datatimepickerdemo; 2 3 import org.apache.http.HttpEntity; 4 import org.apache.http.HttpResponse; 5 import org.apache.http.client.HttpClient; 6 import org.apache.http.client.methods.HttpGet; 7 import org.apache.http.impl.client.DefaultHttpClient; 8 import org.apache.http.util.EntityUtils; 9 10 import android.app.Activity; 11 import android.app.ProgressDialog; 12 import android.graphics.Bitmap; 13 import android.graphics.BitmapFactory; 14 import android.os.AsyncTask; 15 import android.os.Bundle; 16 import android.view.View; 17 import android.widget.Button; 18 import android.widget.ImageView; 19 20 public class AsyncTaskActivity1 extends Activity { 21 private Button btnDown; 22 private ImageView ivImage; 23 private static String image_path = "http://ww4.sinaimg.cn/bmiddle/786013a5jw1e7akotp4bcj20c80i3aao.jpg"; 24 private ProgressDialog dialog; 25 26 @Override 27 protected void onCreate(Bundle savedInstanceState) { 28 // TODO Auto-generated method stub 29 super.onCreate(savedInstanceState); 30 setContentView(R.layout.asynctask_activity); 31 32 btnDown = (Button) findViewById(R.id.btnDown); 33 ivImage = (ImageView) findViewById(R.id.ivSinaImage); 34 35 // 聲明一個等待框以提示用戶等待 36 dialog=new ProgressDialog(this); 37 dialog.setTitle("提示信息"); 38 dialog.setMessage("正在下載,請稍后..."); 39 40 btnDown.setOnClickListener(new View.OnClickListener() { 41 42 @Override 43 public void onClick(View v) { 44 // 執行一個異步任務,並把圖片地址以參數的形式傳遞進去 45 new MyTask().execute(image_path); 46 } 47 }); 48 } 49 50 // 以String類型的參數,Void表示沒有進度信息,Bitmap表示異步任務返回一個位圖 51 public class MyTask extends AsyncTask<String, Void, Bitmap> { 52 // 表示任務執行之前的操作 53 @Override 54 protected void onPreExecute() { 55 super.onPreExecute(); 56 //顯示等待框 57 dialog.show(); 58 } 59 60 //主要是完成耗時操作 61 @Override 62 protected Bitmap doInBackground(String... params) { 63 HttpClient httpClient=new DefaultHttpClient(); 64 HttpGet httpGet=new HttpGet(params[0]); 65 Bitmap bitmap=null; 66 try { 67 //從網絡上下載圖片 68 HttpResponse httpResponse =httpClient.execute(httpGet); 69 if(httpResponse.getStatusLine().getStatusCode()==200){ 70 HttpEntity httpEntity = httpResponse.getEntity(); 71 byte[] data=EntityUtils.toByteArray(httpEntity); 72 bitmap=BitmapFactory.decodeByteArray(data, 0, data.length); 73 } 74 } catch (Exception e) { 75 e.printStackTrace(); 76 } 77 return bitmap; 78 } 79 80 //完成更新UI操作 81 @Override 82 protected void onPostExecute(Bitmap result) { 83 // TODO Auto-generated method stub 84 super.onPostExecute(result); 85 //設置ImageView的顯示圖片 86 ivImage.setImageBitmap(result); 87 // 銷毀等待框 88 dialog.dismiss(); 89 } 90 91 } 92 }
效果展示:
上面的Demo並沒有用到進度的信息,下面再提供一個完整的AsyncTask的Demo,同樣是下載一個圖片,並且展示到一個ImageView中,但是這里在下載的過程中增加一個進度條對話框,用於展示下載的進度。
實現代碼:
1 package com.bgxt.datatimepickerdemo; 2 3 import java.io.ByteArrayOutputStream; 4 import java.io.InputStream; 5 6 import org.apache.http.HttpResponse; 7 import org.apache.http.client.HttpClient; 8 import org.apache.http.client.methods.HttpGet; 9 import org.apache.http.impl.client.DefaultHttpClient; 10 11 import android.app.Activity; 12 import android.app.ProgressDialog; 13 import android.graphics.Bitmap; 14 import android.graphics.BitmapFactory; 15 import android.os.AsyncTask; 16 import android.os.Bundle; 17 import android.view.View; 18 import android.widget.Button; 19 import android.widget.ImageView; 20 21 public class AsyncTaskActivity2 extends Activity { 22 private Button btnDown; 23 private ImageView ivImage; 24 private static String image_path = "http://ww4.sinaimg.cn/bmiddle/786013a5jw1e7akotp4bcj20c80i3aao.jpg"; 25 private ProgressDialog dialog; 26 27 @Override 28 protected void onCreate(Bundle savedInstanceState) { 29 super.onCreate(savedInstanceState); 30 setContentView(R.layout.asynctask_activity); 31 btnDown = (Button) findViewById(R.id.btnDown); 32 ivImage = (ImageView) findViewById(R.id.ivSinaImage); 33 34 dialog = new ProgressDialog(this); 35 dialog.setTitle("提示"); 36 dialog.setMessage("正在下載,請稍后..."); 37 dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); 38 dialog.setCancelable(false); 39 40 btnDown.setOnClickListener(new View.OnClickListener() { 41 42 @Override 43 public void onClick(View v) { 44 // 執行異步任務 45 new MyTask().execute(image_path); 46 } 47 }); 48 } 49 50 public class MyTask extends AsyncTask<String, Integer, Bitmap> { 51 @Override 52 protected void onPreExecute() { 53 super.onPreExecute(); 54 dialog.show(); 55 } 56 57 @Override 58 protected void onProgressUpdate(Integer... values) { 59 super.onProgressUpdate(values); 60 // 設置進度對話框的進度值 61 dialog.setProgress(values[0]); 62 } 63 64 @Override 65 protected void onPostExecute(Bitmap result) { 66 super.onPostExecute(result); 67 dialog.dismiss(); 68 ivImage.setImageBitmap(result); 69 } 70 71 @Override 72 protected Bitmap doInBackground(String... params) { 73 Bitmap bitmap = null; 74 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 75 InputStream inputStream = null; 76 try { 77 HttpClient httpClient = new DefaultHttpClient(); 78 HttpGet httpGet = new HttpGet(params[0]); 79 HttpResponse httpResponse = httpClient.execute(httpGet); 80 if (httpResponse.getStatusLine().getStatusCode() == 200) { 81 inputStream = httpResponse.getEntity().getContent(); 82 long file_length = httpResponse.getEntity() 83 .getContentLength(); 84 int len = 0; 85 byte[] data = new byte[1024]; 86 int total_length = 0; 87 // 以字節的方式讀取圖片數據 88 while ((len = inputStream.read(data)) != -1) { 89 total_length += len; 90 // 計算進度 91 int values = (int) ((total_length / (float) file_length) * 100); 92 // 發布進度信息 93 publishProgress(values); 94 outputStream.write(data, 0, len); 95 } 96 byte[] result=outputStream.toByteArray(); 97 bitmap=BitmapFactory.decodeByteArray(result, 0, result.length); 98 } 99 } catch (Exception e) { 100 e.printStackTrace(); 101 } finally { 102 try { 103 if (inputStream != null) { 104 inputStream.close(); 105 } 106 } catch (Exception e2) { 107 } 108 } 109 return bitmap; 110 } 111 } 112 }
實現效果: