1. 程式人生 > >Android AsyncTask的使用及泛式引數

Android AsyncTask的使用及泛式引數

Android中我們可以通過Theater+Handler來實現多執行緒通訊,當子執行緒的耗時任務完成後通過Handler向主執行緒傳送message,主執行緒收到message後開始更新UI,而為了使程式碼更加統一,我們會使用AsyncTask類。

  1. 什麼是AsyncTask
  2. AsyncTask怎麼用
  3. 需要實現的幾個方法、這些方法有什麼用
  4. 泛型引數
  5. 長度可變的泛式引數
  6. 案例–倒計時Demo

什麼是AsyncTask

  1. AsyncTask是Android提供的輕量級非同步類。
  2. 為了降低非同步通訊的開發難度,提供了AsyncTask。
  3. AsyncTask直接繼承與Object類,位於android.os包中。
  4. 使用AsyncTask可以忽略Looper、MessageQueue、Handler等複雜物件,更便捷地完成耗時操作。

AsyncTask的使用

  1. 新建內部類繼承AsyncTask
  2. 定義AsyncTask的三種泛型引數
  3. 重寫doInBackground抽象方法
  4. 重寫onPreExecute方法
  5. 重寫onProgressUpdate方法
  6. 重寫onPostExecute方法
  7. 在需要啟動的地方呼叫execute方法

需要實現的幾個方法及作用

AsyncTask有四種重要的回撥方法

  • onProgressUpdate
  • doInBackground
  • onPostExecute
  • onPreExecute
    這四個方法會在AsyncTask的不同時期進行自動呼叫,我們只需要實現這幾個方法的內部邏輯即可。這四個方法的一些引數和返回值都是基於泛型的,而且泛型的型別還不一樣,所以在AsyncTask的使用中會遇到三種泛型引數:Params, Progress 和 Result,如下圖所示:
    這裡寫圖片描述

    Params表示用於AsyncTask執行任務的引數的型別
    Progress表示在後臺執行緒處理的過程中,可以階段性地釋出結果的資料型別
    Result表示任務全部完成後所返回的資料型別
    我們通過呼叫AsyncTask的execute()方法傳入引數並執行任務,然後AsyncTask會依次呼叫以下四個方法:
  • onPreExecute
    這裡寫圖片描述
  • doInBackground
    這裡寫圖片描述
  • onProgressUpdate
    這裡寫圖片描述
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <Button android:id="@+id/btnDownload" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="onClick" android:text="開始下載" /> <TextView android:id="@+id/textView" android:layout_below="@id/btnDownload" android:layout_width="match_parent" android:layout_height="wrap_content" /> </RelativeLayout>

java:

public class MainActivity extends Activity implements Button.OnClickListener {

    TextView textView = null;
    Button btnDownload = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView)findViewById(R.id.textView);
        btnDownload = (Button)findViewById(R.id.btnDownload);
        Log.i("iSpring", "MainActivity -> onCreate, Thread name: " + Thread.currentThread().getName());
    }

    @Override
    public void onClick(View v) {
        //要下載的檔案地址
        String[] urls = {
                "http://blog.csdn.net/iispring/article/details/47115879",
                "http://blog.csdn.net/iispring/article/details/47180325",
                "http://blog.csdn.net/iispring/article/details/47300819",
                "http://blog.csdn.net/iispring/article/details/47320407",
                "http://blog.csdn.net/iispring/article/details/47622705"
        };

        DownloadTask downloadTask = new DownloadTask();
        downloadTask.execute(urls);
    }

    //public abstract class AsyncTask<Params, Progress, Result>
    //在此例中,Params泛型是String型別,Progress泛型是Object型別,Result泛型是Long型別
    private class DownloadTask extends AsyncTask<String, Object, Long> {
        @Override
        protected void onPreExecute() {
            Log.i("iSpring", "DownloadTask -> onPreExecute, Thread name: " + Thread.currentThread().getName());
            super.onPreExecute();
            btnDownload.setEnabled(false);
            textView.setText("開始下載...");
        }

        @Override
        protected Long doInBackground(String... params) {
            Log.i("iSpring", "DownloadTask -> doInBackground, Thread name: " + Thread.currentThread().getName());
            //totalByte表示所有下載的檔案的總位元組數
            long totalByte = 0;
            //params是一個String陣列
            for(String url: params){
                //遍歷Url陣列,依次下載對應的檔案
                Object[] result = downloadSingleFile(url);
                int byteCount = (int)result[0];
                totalByte += byteCount;
                //在下載完一個檔案之後,我們就把階段性的處理結果釋出出去
                publishProgress(result);
                //如果AsyncTask被呼叫了cancel()方法,那麼任務取消,跳出for迴圈
                if(isCancelled()){
                    break;
                }
            }
            //將總共下載的位元組數作為結果返回
            return totalByte;
        }

        //下載檔案後返回一個Object陣列:下載檔案的位元組數以及下載的部落格的名字
        private Object[] downloadSingleFile(String str){
            Object[] result = new Object[2];
            int byteCount = 0;
            String blogName = "";
            HttpURLConnection conn = null;
            try{
                URL url = new URL(str);
                conn = (HttpURLConnection)url.openConnection();
                InputStream is = conn.getInputStream();
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                byte[] buf = new byte[1024];
                int length = -1;
                while ((length = is.read(buf)) != -1) {
                    baos.write(buf, 0, length);
                    byteCount += length;
                }
                String respone = new String(baos.toByteArray(), "utf-8");
                int startIndex = respone.indexOf("<title>");
                if(startIndex > 0){
                    startIndex += 7;
                    int endIndex = respone.indexOf("</title>");
                    if(endIndex > startIndex){
                        //解析出部落格中的標題
                        blogName = respone.substring(startIndex, endIndex);
                    }
                }
            }catch(MalformedURLException e){
                e.printStackTrace();
            }catch(IOException e){
                e.printStackTrace();
            }finally {
                if(conn != null){
                    conn.disconnect();
                }
            }
            result[0] = byteCount;
            result[1] = blogName;
            return result;
        }

        @Override
        protected void onProgressUpdate(Object... values) {
            Log.i("iSpring", "DownloadTask -> onProgressUpdate, Thread name: " + Thread.currentThread().getName());
            super.onProgressUpdate(values);
            int byteCount = (int)values[0];
            String blogName = (String)values[1];
            String text = textView.getText().toString();
            text += "\n部落格《" + blogName + "》下載完成,共" + byteCount + "位元組";
            textView.setText(text);
        }

        @Override
        protected void onPostExecute(Long aLong) {
            Log.i("iSpring", "DownloadTask -> onPostExecute, Thread name: " + Thread.currentThread().getName());
            super.onPostExecute(aLong);
            String text = textView.getText().toString();
            text += "\n全部下載完成,總共下載了" + aLong + "個位元組";
            textView.setText(text);
            btnDownload.setEnabled(true);
        }

        @Override
        protected void onCancelled() {
            Log.i("iSpring", "DownloadTask -> onCancelled, Thread name: " + Thread.currentThread().getName());
            super.onCancelled();
            textView.setText("取消下載");
            btnDownload.setEnabled(true);
        }
    }
}

這裡寫圖片描述

泛型引數

AsyncTask是抽象類.AsyncTask定義了三種泛型型別 Params,Progress和Result。
- Params 啟動任務執行的輸入引數,比如HTTP請求的URL。
- Progress 後臺任務執行的百分比。
- Result 後臺執行任務最終返回的結果,比如String,Integer等。

長度可變的泛型引數

可輸入多種引數

protected void onProgressUpdate(String... values)

案例-Demo倒計時

java:
public class Main2Activity extends AppCompatActivity {
    private TextView tv1;
    private Button button;
    int time = 10;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        bindID();
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new DownloadTask().execute();
            }
        });
    }

    private void bindID() {
        button = findViewById(R.id.btn);
        tv1 = findViewById(R.id.tv);

    }


    class DownloadTask extends AsyncTask<String, String, String> {

        @Override
        protected String doInBackground(String... strings) {
            while (time > 0) {
                publishProgress(time + "");
                time--;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return "下載完成";

        }

        @Override
        protected void onProgressUpdate(String... values) {
            super.onProgressUpdate(values);
            tv1.setText(values[0]);
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            tv1.setText(s);
        }
    }

}

xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Main2Activity"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="button"/>
    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>