Android中非同步任務機制AsyncTask的理解
在Android中實現非同步任務機制有兩種方式,Handler和AsyncTask。
Handler模式需要為每一個任務建立一個新的執行緒,任務完成後通過Handler例項向UI執行緒傳送訊息,完成介面的更新,這種方式對於整個過程的控制比較精細,但也是有缺點的,例如程式碼相對臃腫,在多個任務同時執行時,不易對執行緒進行精確的控制。關於Handler的相關知識,前面也有所介紹,不清楚的朋友們可以參照一下。
為了簡化操作,Android1.5提供了工具類android.os.AsyncTask,它使建立非同步任務變得更加簡單,不再需要編寫任務執行緒和Handler例項即可完成相同的任務。
先來看看AsyncTask的定義:
- publicabstractclass AsyncTask<Params, Progress, Result> {
三種泛型型別分別代表“啟動任務執行的輸入引數”、“後臺任務執行的進度”、“後臺計算結果的型別”。在特定場合下,並不是所有型別都被使用,如果沒有被使用,可以用java.lang.Void型別代替。
一個非同步任務的執行一般包括以下幾個步驟:
1.execute(Params... params),執行一個非同步任務,需要我們在程式碼中呼叫此方法,觸發非同步任務的執行。
2.onPreExecute()
3.doInBackground(Params... params),在onPreExecute()完成後立即執行,用於執行較為費時的操作,此方法將接收輸入引數和返回計算結果。在執行過程中可以呼叫publishProgress(Progress... values)來更新進度資訊。
4.onProgressUpdate(Progress... values),在呼叫publishProgress(Progress... values)時,此方法被執行,直接將進度資訊更新到UI元件上。
5.onPostExecute(Result result),當後臺操作結束時,此方法將會被呼叫,計算結果將做為引數傳遞到此方法中,直接將結果顯示到UI元件上。
在使用的時候,有幾點需要格外注意:
1.非同步任務的例項必須在UI執行緒中建立。
2.execute(Params... params)方法必須在UI執行緒中呼叫。
3.不要手動呼叫onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values),onPostExecute(Result result)這幾個方法。
4.不能在doInBackground(Params... params)中更改UI元件的資訊。
5.一個任務例項只能執行一次,如果執行第二次將會丟擲異常。
接下來,我們來看看如何使用AsyncTask執行非同步任務操作,我們先建立一個專案,結構如下:
結構相對簡單一些,讓我們先看看MainActivity.java的程式碼:
- package com.scott.async;
- import java.io.ByteArrayOutputStream;
- import java.io.InputStream;
- import org.apache.http.HttpEntity;
- import org.apache.http.HttpResponse;
- import org.apache.http.HttpStatus;
- import org.apache.http.client.HttpClient;
- import org.apache.http.client.methods.HttpGet;
- import org.apache.http.impl.client.DefaultHttpClient;
- import android.app.Activity;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.util.Log;
- import android.view.View;
- import android.widget.Button;
- import android.widget.ProgressBar;
- import android.widget.TextView;
- publicclass MainActivity extends Activity {
- privatestaticfinal String TAG = "ASYNC_TASK";
- private Button execute;
- private Button cancel;
- private ProgressBar progressBar;
- private TextView textView;
- private MyTask mTask;
- @Override
- publicvoid onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- execute = (Button) findViewById(R.id.execute);
- execute.setOnClickListener(new View.OnClickListener() {
- @Override
- publicvoid onClick(View v) {
- //注意每次需new一個例項,新建的任務只能執行一次,否則會出現異常
- mTask = new MyTask();
- mTask.execute("http://www.baidu.com");
- execute.setEnabled(false);
- cancel.setEnabled(true);
- }
- });
- cancel = (Button) findViewById(R.id.cancel);
- cancel.setOnClickListener(new View.OnClickListener() {
- @Override
- publicvoid onClick(View v) {
- //取消一個正在執行的任務,onCancelled方法將會被呼叫
- mTask.cancel(true);
- }
- });
- progressBar = (ProgressBar) findViewById(R.id.progress_bar);
- textView = (TextView) findViewById(R.id.text_view);
- }
- privateclass MyTask extends AsyncTask<String, Integer, String> {
- //onPreExecute方法用於在執行後臺任務前做一些UI操作
- @Override
- protectedvoid onPreExecute() {
- Log.i(TAG, "onPreExecute() called");
- textView.setText("loading...");
- }
- //doInBackground方法內部執行後臺任務,不可在此方法內修改UI
- @Override
- protected String doInBackground(String... params) {
- Log.i(TAG, "doInBackground(Params... params) called");
- try {
- HttpClient client = new DefaultHttpClient();
- HttpGet get = new HttpGet(params[0]);
- HttpResponse response = client.execute(get);
- if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
- HttpEntity entity = response.getEntity();
- InputStream is = entity.getContent();
- long total = entity.getContentLength();
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- byte[] buf = newbyte[1024];
- int count = 0;
- int length = -1;
- while ((length = is.read(buf)) != -1) {
- baos.write(buf, 0, length);
- count += length;
- //呼叫publishProgress公佈進度,最後onProgressUpdate方法將被執行
- publishProgress((int) ((count / (float) total) * 100));
- //為了演示進度,休眠500毫秒
- Thread.sleep(500);
- }
- returnnew String(baos.toByteArray(), "gb2312");
- }
- } catch (Exception e) {
- Log.e(TAG, e.getMessage());
- }
- returnnull;
- }
- //onProgressUpdate方法用於更新進度資訊
- @Override
- protectedvoid onProgressUpdate(Integer... progresses) {
- Log.i(TAG, "onProgressUpdate(Progress... progresses) called");