1. 程式人生 > >非同步任務載入網路資料——AsyncTask使用

非同步任務載入網路資料——AsyncTask使用

AsyncTask類簡單介紹

  • Android從1.5開始引入了AsyncTask這個類,AsyncTask內部使用Java 1.5的併發庫比普通初級Android開發者編寫的Thread+Handler穩定很多
  • AsyncTask封裝了Thread和Handler,使我們用起來更加方便,不用去關注Handler。由於後臺執行緒不能更新UI,而很多情況下,我們在後臺執行緒做完一件事後,一般都會更新UI,一般我們會這樣做:在UI執行緒建立一個handler物件,在後臺執行緒中傳送一條message,再在Handler中去處理這個message,進而更新UI。
  • 用了AsyncTask後,我們就不用再去關注Handler了。它定義了三種泛型,分別是Params、Progress和Result,分別表示請求的引數、任務的進度和獲得的結果資料。

一、使用AsyncTask的好處

  1. 底部封裝了執行緒池技術,其中的方法很容易呼叫。
  2. 直接呼叫相關方法,進行UI介面的更新。
  3. 一旦任務多,就不用每次都new新的執行緒,可以直接使用。

二、執行順序

onPreExecute()【執行前開啟】 ---> doInBackground() ---> onProgressUpdate() ---> onPostExecute()

三、實現原理:

1.執行緒池的建立:
    在建立了AsyncTask的時候,會預設建立一個執行緒池ThreadPoolExecutor,並預設創建出5個執行緒放入到執行緒池中,最多可防128個執行緒;且這個執行緒池是公共的唯一一份。

2.任務的執行:
    在execute中,會執行run方法,當執行完run方法後,會呼叫scheduleNext()不斷的從雙端佇列中輪詢,獲取下一個任務並繼續放到一個子執行緒中執行,直到非同步任務執行完畢。

3.訊息的處理:
    在執行完onPreExecute()方法之後,執行了doInBackground()方法,然後就不斷的傳送請求獲取資料;在這個AsyncTask中維護了一個InternalHandler的類,這個類是繼承Handler的,獲取的資料是通過handler進行處理和傳送的。在其handleMessage方法中,將訊息傳遞給onProgressUpdate()進行進度的更新,也就可以將結果傳送到主執行緒中,進行介面的更新了。

四、AsyncTask工作原理詳解

  1. onPreExecute(): 在UI執行緒裡面呼叫,它在這個task執行後會立即呼叫。我們在這個方法裡面通常是用於建立一個任務,比如顯示一個等待對話方塊來通知使用者。

  2. doInBackground(Params…):這個方法從名字就可以看出,它是執行在後臺執行緒的,在這個方法裡面,去做耗時的事情,比如下載訪問網路,操作檔案等。在這個方法裡面,我們可以呼叫publishProgress(Progress…)來呼叫當前任務的進度,呼叫了這個方法後,對應的onProgressUpdate(Progress…)方法會被呼叫,這個方法是執行在UI執行緒的。

  3. onProgressUpdate(Progress…):執行在UI執行緒,在呼叫publishProgress()方法之後。這個方法用來在UI上顯示任何形式的進度,比如你可以顯示一個等待對話方塊,也可以顯示一個文字形式的log,還可以顯示toast對話方塊。

  4. onPostExecute(Result):當task結束後呼叫,它執行在UI執行緒。

  5. 取消一個task,我們可以在任何時候呼叫cancel(Boolean)來取消一個任務,當呼叫了cancel()方法後,onCancelled(Object)方法就會被呼叫,onPostExecute(Object)方法不會被呼叫,在doInBackground(Object[])方法中,我們可以用isCancelled()方法來檢查任務是否取消。

小主意:

  • AsyncTask例項必須在UI執行緒中建立
  • execute(Params…)方法必須在UI執行緒中呼叫。
  • 不用手動呼叫onPreExecute() doInBackground() onProgressUpdate() onPostExecute()方法。
  • 一個任務只能被執行一次。

示例程式碼

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView    
       android:layout_width="fill_parent"   
       android:layout_height="wrap_content"   
       android:text="Hello , Welcome to Andy's Blog!"/>  
    <Button  
       android:id="@+id/download"  
       android:layout_width="fill_parent"  
       android:layout_height="wrap_content"  
       android:text="Download"/>  
    <TextView    
       android:id="@+id/tv"  
       android:layout_width="fill_parent"   
       android:layout_height="wrap_content"   
       android:text="當前進度顯示"/>  
    <ProgressBar  
       android:id="@+id/pb"  
       android:layout_width="fill_parent"  
       android:layout_height="wrap_content"  
       style="?android:attr/progressBarStyleHorizontal"/>  
</LinearLayout>
package sn.demo;

import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ProgressBar;
import android.widget.TextView;

public class DownloadTask extends AsyncTask<Integer, Integer, String> {
    //後面尖括號內分別是引數(執行緒休息時間),進度(publishProgress用到),返回值 型別  

    private Context mContext=null;
    private ProgressBar mProgressBar=null;
    private TextView mTextView=null;
    public DownloadTask(Context context,ProgressBar pb,TextView tv){
        this.mContext=context;
        this.mProgressBar=pb;
        this.mTextView=tv;
    }
    /*
     * 第一個執行的方法
     * 執行時機:在執行實際的後臺操作前,被UI 執行緒呼叫
     * 作用:可以在該方法中做一些準備工作,如在介面上顯示一個進度條,或者一些控制元件的例項化,這個方法可以不用實現。
     * @see android.os.AsyncTask#onPreExecute()
     */
    @Override
    protected void onPreExecute() {
        // TODO Auto-generated method stub
        Log.d("sn", "00000");
        super.onPreExecute();
    }

    /*
     * 執行時機:在onPreExecute 方法執行後馬上執行,該方法執行在後臺執行緒中
     * 作用:主要負責執行那些很耗時的後臺處理工作。可以呼叫 publishProgress方法來更新實時的任務進度。該方法是抽象方法,子類必須實現。
     * @see android.os.AsyncTask#doInBackground(Params[])
     */
    @Override
    protected String doInBackground(Integer... params) {
        // TODO Auto-generated method stub
        Log.d("sn", "1111111");
        for(int i=0;i<=100;i++){
            mProgressBar.setProgress(i);
            publishProgress(i);
            try {
                Thread.sleep(params[0]);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return "執行完畢";
    }

    /*
     * 執行時機:這個函式在doInBackground呼叫publishProgress時被呼叫後,UI 執行緒將呼叫這個方法.雖然此方法只有一個引數,但此引數是一個數組,可以用values[i]來呼叫
     * 作用:在介面上展示任務的進展情況,例如通過一個進度條進行展示。此例項中,該方法會被執行100次
     * @see android.os.AsyncTask#onProgressUpdate(Progress[])
     */
    @Override
    protected void onProgressUpdate(Integer... values) {
        // TODO Auto-generated method stub
        Log.d("sn", "2222222222");
        mTextView.setText(values[0]+"%");
        super.onProgressUpdate(values);
    }

    /*
     * 執行時機:在doInBackground 執行完成後,將被UI 執行緒呼叫
     * 作用:後臺的計算結果將通過該方法傳遞到UI 執行緒,並且在介面上展示給使用者
     * result:上面doInBackground執行後的返回值,所以這裡是"執行完畢"  
     * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
     */
    @Override
    protected void onPostExecute(String result) {
        // TODO Auto-generated method stub
        Log.d("sn", "3333333333");

        super.onPostExecute(result);
    }
}
package sn.demo;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

public class AsyncTaskDemoActivity extends Activity {
    /** Called when the activity is first created. */
    private Button download;
    private TextView tv;
    private ProgressBar pb;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        initView();
    }
    private void initView() {
        // TODO Auto-generated method stub
        tv=(TextView)findViewById(R.id.tv);
        pb=(ProgressBar)findViewById(R.id.pb);
        download=(Button)findViewById(R.id.download);
        download.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                DownloadTask dt=new DownloadTask(AsyncTaskDemoActivity.this,pb,tv);
                dt.execute(100);
            }
        });
    }
}