Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中的AsyncTask和接口回調使用詳解

Android中的AsyncTask和接口回調使用詳解

編輯:關於Android編程

一、AsyncTask簡單介紹

官方文檔中隊AsyncTask的解釋是:AsyncTask更加適用於UI線程。這個類允許執行後台操作並在UI界面上發布結果,而不必處理多線程。AsyncTask是圍繞Thread和Handler設計的一個輔助類,它不構成一個通用的線程框架。Asynctasks應該用於短作業(最多幾秒鐘)。

說的簡單一點,AsyncTask其實就是Android提供的一個輕量級異步類。使用的時候可以自己自定義一個類去繼承AsyncTask,就能在自定義類中實現異步操作,並且該類的實現方法中提供了接口來反饋當前異步任務執行的程度,最後還可以將執行的結果傳遞給UI線程。

二、接口回調簡單介紹

接口回調,字面意思可以理解為定義一個接口,等以後出現了某一種狀況的時候,然後去調用接口的方法做一些事。 多個比方說,我是搞開發的,目前手裡沒有項目,我就打電話奧巴馬問他手裡有沒有項目給我做,要是他手裡有項目就直接給我了,要是沒有他會說後面可能有,你留下電話,有了我就打電話告訴你,這就是一個簡單的回調理解,奧巴馬後面打電話給我就相當於一個回調過程,而我打電話給奧巴馬就相當於注冊接口。 在Demo中,接口回調使用在異步任務執行完畢之後。因為你備份完短信可能要談個吐司,播個音樂什麼的,那就必須讓MainActivity知道你已經執行完任務了,但是MainActivity怎麼知道你已經執行完了,這裡就需要接口回調了,讓MainActivity實現接口,並且先定義好當完成任務需要做什麼事情。這樣當任務執行完就會直接調用MainActivity中定義好的方法更新UI等操作。短信備份操作回調結構圖如下:

 

三、AsyncTask和接口回調的使用案例

先來看一下使用AsyncTask顯示備份短信和還原短信的進度條。實現的原理很簡單,寫一個短信的工具類,在類中提供從數據庫讀取短信到集合和還原保存的短信到集合的方。我們自定義兩個類繼承AsyncTask,一個類實現將集合中的短信保存到本地的邏輯,另一個類實現將將集合中的短信插入到數據庫中的邏輯。並且當異步任務執行完畢之後,我們使用接口回調,讓主線程去處理短信備份和還原完成的工作,這裡是談吐司,當然你也可以播放音樂什麼的。

 

四、AsyncTask使用詳解

官方文檔中稱:異步任務將耗時操作放在後台線程上計算運行,然後將其結果在用戶界面線程上發布。一個異步任務是由參數,過程和結果這3個泛型類型定義。它還包括四個步驟:oPostExecute,doInBackground,onProgressUpdate和onPostexecute。使用AsyncTask必須定義一個類繼承AsyncTask,然後子類中必須實現doInBackground方法,經常也會實現oPostExecute方法。

自定義類繼承AsyncTask代碼如下:

private class DownloadFilesTask extends AsyncTask {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
    }
 }

開啟異步任務代碼如下:

new DownloadFilesTask().execute(url1, url2, url3);

1. 三個泛型類型

Params:參數。啟動任務執行需要輸入的參數,比如HTTP請求的URL Progress:過程。後台任務執行的百分比

Result:結果。後台執行任務最終返回的結果,比如String

這三個參數對四個步驟的方法的參數類型和返回值分別進行約束,如果沒有約束的話,參數類型都為Void

private class MyTask extends AsyncTask { ... }

2. 四個步驟

onPreExecute()

調用時機:第一個執行,並且在異步任務開始之前調用 執行線程:主線程 方法參數:無 方法返回值:無

方法的作用:用於提醒用戶,當前正在請求數據,一般用來彈出進度對話框

@Override
protected void onPreExecute() {
    super.onPreExecute();
    // 運行在前台,初始化UI操作
    mDialog = new ProgressDialog(context);
    mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    mDialog.show();
}

doInBackground()

調用時機:在onPreExecute方法執行完畢之後,這個方法一定會執行 執行線程:子線程

方法參數

由類上面的第一個泛型Params來限定 從execute方法裡面傳遞進來

方法返回值

由類上面的第三個泛型Result來限定 將被當做onPostExecute()方法的參數

方法的作用:在後台線程當中執行耗時操作,比如聯網請求數據。在執行過程中可以調用publicProgress()來更新任務的進度

@Override
protected Boolean doInBackground(Void... params) {

    List list = SmsUtil.getAllSms(context);

    try {
        // 序列化器
        XmlSerializer xs = Xml.newSerializer();
        File file = new File(context.getFilesDir(), "sms.xml");
        // 設置輸出路徑
        xs.setOutput(new FileOutputStream(file), "utf-8");

        xs.startDocument("utf-8", true);

        xs.startTag(null, "smss");

        for (int i = 0; i < list.size(); i++) {

            SmsBean bean = list.get(i);

            xs.startTag(null, "sms");

            xs.startTag(null, "address");
            xs.text(bean.address);
            xs.endTag(null, "address");

            xs.startTag(null, "date");
            xs.text(bean.date + "");
            xs.endTag(null, "date");

            xs.startTag(null, "type");
            xs.text(bean.type + "");
            xs.endTag(null, "type");

            xs.startTag(null, "body");
            xs.text(bean.body);
            xs.endTag(null, "body");

            xs.endTag(null, "sms");

            SystemClock.sleep(100);

            publishProgress(i + 1, list.size());
        }

        xs.endTag(null, "smss");
        xs.endDocument();

        return true;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}

onProgressUpdate()

調用時機:在publishProgress()方法執行之後調用 執行線程:主線程

方法參數

由類上面的第二個泛型來限定。 參數是從publishProgress 傳遞進來 方法返回值:無

方法的作用:更新進度條

@Override
protected void onProgressUpdate(Integer... values) {
    super.onProgressUpdate(values);
    // 更新UI
    mDialog.setMax(values[1]);
    mDialog.setProgress(values[0]);
}   

onPostExecute()

調用時機:在doInBackground 執行完畢之後調用 執行線程:主線程

方法參數

由類上面的第三個泛型來限定。 doInBackground的返回值就是這個方法的參數

方法返回值:無

方法的作用:相當於Handler的handleMessage()方法,在這裡面可以對doInBackground()方法得到的結果進行處理,更新UI

@Override
protected void onPostExecute(Boolean result) {
    super.onPostExecute(result);
    if (result) {
        listener.onSuccess();
    } else {
        listener.onFailure();
    }
    mDialog.dismiss();
}

3. 需要遵守的准則

任務必須在主線程中執行 任務對象必須在主線程中構建 execute方法必須在主線程中執行 四個步驟中的方法不能直接調用,publicProgress()方法可以在類中暴露一個方法出去,讓外邊調用

任務只能執行一次

1.6開始的時候,可以並發執行多個任務,但是3.0之後,只能允許單個任務執行。如果真的想要多任務並發執行,那麼可以運行在自己的線程池裡面

mTask.executeOnExecutor(exec, params)

五、接口回調簡單使用

使用接口回調,一般有以下四個步驟,通過這四個步驟就能形成一個簡單的回調。在Android中很多地方都用到了接口回調,比如控件的點擊事件,GitHub上的許多開源框架也都用了接口回調,開發過程了也頻頻涉及到接口回調,所以這是一個很重要的知識點。

定義接口,可以是內部接口,也可以是自定義接口

/**
 * 定義回調接口
 */
public interface OnTaskListener{

    /**
     * 成功之後調用這個方法
     */
    void onSuccess();

    /**
     * 失敗之後調用這個方法
     */
    void onFailed();


}

接收接口實現類對象

public BackupTask(Context context, OnTaskListener listener) {
        mContext = context;
        mListener = listener;
}

通過接口實現類對象,訪問對應的方法

if(result){
    mListener.onSuccess();
    // == ToastUtil.showShort(mContext,"備份成功");
}else{
    mListener.onFailed();
    // == ToastUtil.showShort(mContext,"備份失敗");
}

在實現中編寫調用方法執行操作的代碼

// 直接調用工具類的回調方法來彈出吐司
new SmsUtil().backUpSms(this, new SmsUtil.OnTaskListener() {
    @Override
    public void onSuccess() {
        ToastUtil.showShort(MainActivity.this,"備份成功");
    }

    @Override
    public void onFailure() {
        ToastUtil.showShort(MainActivity.this,"備份失敗");
    }
});
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved