Android的異步任務AsyncTask

AsyncTask,顧名思義,異步任務。說到異步,最簡單的理解就是不一樣步。再複雜一點理解,就得舉例子了。html

假設我要去火車站買票,剛到火車站我忽然發現我忘了帶身份證。怎麼辦?怎麼辦!java

想辦法,想辦法!我想我應該找個在學校的同窗幫我送過來,由於我不能本身回去拿啊,還要排隊呢,走不開。嗯,要找人送過來。可是問題來了,我找人送身份證了,我去排隊了,若是排到第一位了身份證還沒到怎麼辦?叮,腦殼上面忽然亮了一個小燈泡,機智的我在排隊前想到了兩種方案:android

第一種方案,讓售票員等着我,我後面隊伍裏買票的人也等着我,我一直在窗口第一位置等着同窗來送身份證,直到,個人身份證被送來,而後順利買票。json

另外一種方案呢,就是我跟售票員說一下,讓我在一邊等着送身份證,後面的人繼續買票,等個人身份證送來的時候我通知下售票員,就能夠儘快排到隊伍第一位(不必定是當即排到第一位,由於萬一有人正在買票,我不能過去打斷他)而後買票。數組

因此呢,選第一種仍是第二種?我確定選第二種,由於選第一種確定會被後面排隊的人罵死,並且還有可能被售票員罵,搞很差還會捱揍,畢竟由於我一我的,浪費了這麼多人的時間,也拖慢了售票員的工做效率。網絡

好了,例子就說到這裏。在例子裏,第二種方法就是異步的。異步每每和多線程有關,並且異步任務也大可能是交由一個單獨的線程完成,而後返回結果給主線程。這裏售票員至關於cpu,而排隊買票的人至關於等待被執行的任務,而我是個被標記爲異步的任務(由於我知道我帶身份證,不能當即買到票,因此排隊前就想好了第二種方案),當cpu執行到我這個任務的時候,發現我這個任務可執行的條件(身份證)不具有,因此由我發起了一個異步任務(同窗送票),去獲取可執行的條件,以後當即把位置讓出來,讓其餘排隊的任務繼續執行。直到個人身份證拿來,而後立馬通知cpu準備接待我。多線程

嗯,差很少就是這樣了。開始說正文,android裏面的AsyncTask。先上一段官網的引用:異步

AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.ide

是英語,雖然我能懂大概是什麼意思,可是仍是不翻譯了,怕誤人子弟,等我英語學的再好些再來翻譯吧。不過仍是要解釋下大概的意思,就是說AsyncTask能夠在UI線程上作一些後臺操做,也能返回操做結果到UI線程上。咱們知道UI線程是不能作一些耗時的操做的,可是有了AsyncTask,咱們能夠這樣作了。可是,url

AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.

對於耗時比較久的任務,仍是不建議放在AsyncTask中執行。AysncTask被設計成Thread和Handler的輔助類,並不能執行過於複雜和耗時的任務,這種任務應該用其餘方法這裏就不說了。AsyncTask最好用於耗時最多隻有幾秒鐘的操做,好比向網絡請求個xml或是json之類的網絡操做,或是用在程序的初始化界面等等。

下面說下AsyncTask的使用。其實很簡單。

首先你須要定義一個AsyncTask的子類,而且必須重寫父類的doInBackground(Params...)方法。另外還有onPostExecute(Result)方法也可重寫,這個方法在doInBackground以後被自動調用,因此你能夠在這裏寫一些任務完成的通知代碼。

先給一個官方的例子:

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
    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");
    }
 }

執行AsyncTask的時候,必須在UI線程中執行,以下語句。

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

能夠看到,在繼承AsyncTask的時候,有幾個泛型類型,如AsyncTask<URL, Integer, Long>,簡單解釋下。

  1. 第一個能夠指定輸入參數的類型,就是new DownloadFilesTask().execute()的參數(最後傳到了doInBackground),這裏的參數能夠不僅一個,由於最後到方法裏面,收到的是個數組。
  2. 第二個可指定發送進度更新須要的類型,通常都是整型,用在publishProgress(用來在後臺進程中發送進度的方法,直接使用的,不用定義)和onProgressUpdate兩個方法中。
  3. 第三個是AsyncTask返回結果的數據類型,它設置了doInBackground的返回類型,以及onPostExecute的輸入參數類型

固然,若是你什麼都不須要,能夠都使用Void

private class MyTask extends AsyncTask<Void, Void, Void> { ... }

另外,還有一個能夠重寫的方法,是onPreExecute(),它在doInBackground以前被調用,因此若是須要的話,你能夠重寫它而後作一些實例化進度條啊之類的工做。

最後,總結一下:

使用AsyncTask,你要作的是,繼承父類,而後重寫doInBackground(Params...),在裏面實現後臺操做,若是有返回結果的話,重寫onPostExecute(Result)而後處理後臺程序的結果。

若是須要更新進度的話,在onPreExecute()裏實例化進度條(也能夠不在這),以後在doInBackground(Params...)裏面用publishProgress()發佈進度值,而後重寫onProgressUpdate(Progress...)接收onPreExecute()發佈的結果,並添加更新進度條的代碼。

相關文章
相關標籤/搜索