Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> AsyncTask使用及源碼解析

AsyncTask使用及源碼解析

編輯:關於Android編程

AsyncTask介紹及使用

AsyncTask是什麼?異步任務,在android中主線程不能做耗時的操作,否則很容易出現ANR異常,所以像訪問網絡,讀取數據庫等一些耗時的操作都放在子線程中,但是子線程是無法更新UI的,我們還需要把得到的結果發送到主線程中做更新UI的處理。這時我們就需要用到Handler或者AsnycTask,其實AsyncTask是對Handler和Thread做了封裝,更加方便調用。

1. AsyncTask API介紹

構造方法
public abstract class AsyncTask
//三個泛型分別表示: 啟動任務執行的輸入參數 , 後台任務執行的進度 , 後台任務執行結果
普通方法
(1). execute(Params... params)   
    // 調用該方法來啟動執行異步方法

(2). onPreExecute() ;  
    // 在execute(Params... params)方法調用之後立即執行的方法,該方法在主線程中執行,

(3). doInBackground(Params... params); 
    // 在onPreExecute()執行之後執行的方法,該方法在子線程中執行,可以用來做一些耗時的操作;在該方法中可以調用publishProgress(Progress... vallues)來更新進度等,

(4). onProgressUpdate(Progress... values);
     // 在調用publishProgress(Progress... values),該方法在UI線程中執行,用來更新進度

(5). onPostExecute(Result result); 
    // 後台執行結束時,該方法調用,在UI線程中執行。後台計算結果被作為參數傳遞給該方法。

(6). onCancelled(); 
    // 當任務取消時調用該方法
使用時注意事項:
(1). 異步任務的實例對象必須在主線程中創建;
(2). execute(Params… params)方法必須在主線程中調用;
(3). 不要手動調用onPreExecute(),doInBackground(Params… params),onPostExecute(Result result)這幾個方法;
(4). doInBackground(Params… params)方法是在子線程中執行的,所以不能做更新UI的操作;
(5). 一個異步任務實例只能執行一次,如果 第二次就會拋出異常;

2. 使用實例

public class MainActivity extends Activity implements View.OnClickListener {

    private ProgressBar pb ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        pb = (ProgressBar) findViewById(R.id.pb);
        pb.setMax(100);
        findViewById(R.id.btn1).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        asyncTask.execute(); // 調用execute()方法啟動異步任務;
    }

    private AsyncTask asyncTask = new AsyncTask() {

        @Override
        protected void onPreExecute() {
            showToast("調用execute()方法執行異步任務,該方法立即在主線程中執行");
        }

        @Override
        protected String doInBackground(Void... v) {
            for(int i=0 ;i<=100;i++){
                SystemClock.sleep(500);    // 模擬耗時操作
                publishProgress(i);      //調用該方法更新進度
            }
            return "執行完成";
        }

        @Override  // 該方法在調用publishProgress()方法調用之後執行,執行在主線程接收publishProgress()傳遞的參數,用來更新UI界面
        protected void onProgressUpdate(Integer... values) {   
            pb.setProgress(values[0]);
        }

        @Override  // 該方法在doInBackground()方法執行結束後執行,接受其傳遞的參數,該方法在主線程中執行
        protected void onPostExecute(String s) {
            showToast(s);
        }
    };

    /**
     * 顯示Toast
     * @param msg
     */
    private void showToast(String msg){
        Toast.makeText(this , msg , Toast.LENGTH_SHORT).show();
    }

}

3 . 仿AsyncTask

剛才說過AsyncTask其內部是對線程和Handler的封裝,簡化我們的使用。現在我們自己來實現一個AsyncTask,以便更好的了解其內部實現原理。
AsyncTask在使用過程中常用的那幾個方法執行順序以及是否執行在UI線程中我們已經做了了解,我們知道在調用execute()的時候開啟異步任務,首先調用的就是onPreExecute()方法,然後在子線程中執行doInBackground()方法,在執行過程中調用publishProgress()方法將執行進度發送到主線程中,通過onProgressUpdate()方法來更新UI;在doInBackground()方法執行完畢以後,執行onPostExecute()方法,將執行結果作為參數傳遞給onPostExecute()。這就是AsyncTask執行流程,下面就是我們自己實現的MyAsyncTask

public abstract class MyAsyncTask {

    private static InteranlHandler interHandler ;  // 內部封裝Handler用來發送消息,在主線程中更新UI
    private static final int MSG_PROGRESS = 0 ;  // 發送更新UI進度類型的類型
    private static final int MSG_RESULT = 1 ;   // 發送執行結果的消息類型

    public MyAsyncTask(){
        interHandler = new InteranlHandler(); // 在創建實例時,內部創建Handler對象
    }

    /**
     * 調用execute方法,觸發異步任務執行
     * @param params
     */
    public void execute(final Params... params){
        onPreExecute();             // 首先調用onProExecute()方法
        new Thread(){
            @Override
            public void run() {
                Result result = doInBackground(params);  // 在子線程中執行doInBackground方法,將獲取的結果通過finish(Result)方法發送到主線程中
                finish(result);
            }
        }.start();
    }

    /**
    *通過AsyncTaskResult將數據封裝起來發送到主線程中
    */
    private void finish(final Result result){
            AsyncTaskResult taskResult = new AsyncTaskResult(MyAsyncTask.this , result);
            Message msg = Message.obtain();
            msg.what = MSG_RESULT ;
            msg.obj = taskResult ;
            interHandler.sendMessage(msg);
        }


    /**
     * execute方法執行之前立即在mainTread中執行,
     */
    protected void onPreExecute(){

    }

    /**
     * 在子線程中執行
     * @param paramses
     * @return
     */
    protected abstract Result doInBackground(Params... paramses);

    /**
     * 更新UI,在主線程中執行
     * @param progress
     */
    protected void onProgressUpdate(Progress... progress){

    }

    /**
     * 調用該方法,將數據封裝起來,發送到主線程中,觸發onProgressUpdate方法在主線程中執行
     * @param progress
     */
    protected void publishProgress(final Progress... progress){
        AsyncTaskResult result = new AsyncTaskResult(MyAsyncTask.this , progress);
        Message msg = Message.obtain();
        msg.what = MSG_PROGRESS ;
        msg.obj = result ;
        interHandler.sendMessage(msg);
    }

    /**
     * doInBackground執行結束後,將結果作為參數傳遞給該方法,觸發該方法在主線程中執行
     * @param result
     */
    protected void onPostExecute(Result result){

    }


    private static class InteranlHandler extends Handler{

        public InteranlHandler(){
            super(Looper.getMainLooper());
        }

        @Override
        public void handleMessage(Message msg) {
            AsyncTaskResult result = (AsyncTaskResult) msg.obj;
            switch (msg.what){
                case MSG_PROGRESS : // 在Handler中接受消息,調用onProgressUpdate()方法更新進度
                    result.asyncTask.onProgressUpdate(result.mData);
                    break;
                case MSG_RESULT : // 調用OnPostExecute()方法將將結果作為參數傳遞給OnPostExecute(Result)
                    result.asyncTask.onPostExecute(result.mData[0]);
                    break;
            }
        }
    };

    /**
     * 對數據進行封裝
     * @param 
     */
    private static class AsyncTaskResult{
        public MyAsyncTask asyncTask ;
        public Data[] mData ;
        public AsyncTaskResult(MyAsyncTask task , Data... datas){
            this.asyncTask = task ;
            this.mData = datas ;
        }
    }

}

這樣就完成了我們自己的AsyncTask,使用方式和AsyncTask一樣。

//創建實例,然後調用execute(Params... params)方法觸發異步任務執行,
 private MyAsyncTask myAsyncTask = new MyAsyncTask() {

        @Override
        protected void onPreExecute() {
            showToast("MyAsyncTask  執行onPreExecute方法,在主線程中執行");
        }

        @Override
        protected String doInBackground(Void... voids) {
            for(int i=0;i<=100;i++){
                SystemClock.sleep(500);
                publishProgress(i);
            }
            return "MyAsycTask後台方法執行完畢";
        }

        @Override
        protected void onProgressUpdate(Integer... progress) {
            pb.setProgress(progress[0]);
        }

        @Override
        protected void onPostExecute(String result) {
            showToast(result);
        }
    };

4. AsyncTask源碼解析

當我們完成了仿AsyncTask之後,我們對AsyncTask內部實現原理也就一目了然了。AsyncTask內部就是對線程池和Handler的封裝,調用execute方法時,內部會調用executeOnExecutor()方法,該方法執行後,會先調用onPreExecute()方法;然後執行FutureTask任務,這個過程中doInBackground(Params… params)會被調用,如果我們在doInBackground方法中調用publishProgress(Progress… values)方法,內部會通過InternalHandler(繼承Handler)實例來發送一條MESSAGE_POST_PROGRESS消息,更新進度,在InternalHandler中處理消息時,會調用onProgressUpdte(Progress… progress)方法,doInBackground()方法執行完畢後,會發送一條MESSAGE_POST_RESULT消息處理結果,InternalHandler在處理結果時,會調用onPostExecute()方法。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved