AsyncTask面試知識小結

前言

今天我們來回顧複習下AsyncTask, 它是Android 一種輕量級的異步任務類,從實現來說,AsyncTask封裝了線程池和Handler。它可以在線程池中執行後臺任務,把執行的進度和結果傳遞給主線程並在主線程中更新UI,通過AsyncTask可以更加方便的執行後臺任務以及在主線程訪問UI,但他不適合進行特別耗時的後臺任務。

一、什麼是AsyncTask?

1、是一種輕量級的異步任務類;
2、是一個封裝了線程池和Handler的異步框架;
3、使用它可以更加方便的執行後臺任務以及在主線程訪問UI,但他不適合進行特別耗時的後臺任務;

二、AsyncTask的使用方法

1、3個參數
  • Params:執行AsyncTask時,後臺任務需要傳入的參數,在doInBackground中取出使用。
  • Progress:後臺任務執行時,如果需要顯示當前進度,則制定進度的數據類型。
  • Result:後臺任務執行完成後的返回值類型。
2、5個方法
  • onPreExecute:
    在主線程中執行,在後臺任務執行前調用,通常用於做一些準備操作。

  • doInBackground(Params… params):
    在線程池中執行,用於執行後臺任務;params 參數是 execute(Params… params)方法中傳遞的參數。在此方法中可以調用 publishProgress 方法來更新任務的進度,publishProgress方法會調用onProgressUpdate方法。

  • publishProgress(Progress… values):
    用於更新任務的進度,需要手動調用,publishProgress方法會調用onProgressUpdate方法;values參數爲設置的進度值。

  • onProgressUpdate(Progress… values):
    在主線程中執行,當後臺任務的執行進度發生改變時,會被調用,values參數爲進度值。

  • onPostExecute(Result result):
    在主線程中執行,當後臺任務執行完成時,會被調用。result 的值是doInBackground的返回值。

三、AsyncTask的機制原理

  • AsyncTask 的本質是一個靜態的線程池,可以執行不同的異步任務,這些任務提交到靜態的線程池中執行。
  • 線程池中的工作線程執行doInBackgroup(Params… params)方法執行異步任務。
  • 當任務狀態改變後,工作線程向UI線程發送消息,AsyncTask內部的InternalHandler 響應這些消息,並調用相關的回調函數。

四、AsyncTask的注意事項

1、內存泄漏
  • 原因:非靜態內部類持有外部類的匿名引用,導致Activity無法釋放。

  • 解決:

    • AsyncTask內部持有外部Activity的弱引用。
    • AsyncTask改爲靜態內部類。
    • AsyncTask.cancel()。
2、生命週期

不受Activity生命週期的影響,在Activity銷燬之前,取消AsyncTask的運行,以此來保證程序的穩定。

3、結果丟失

由於屏幕旋轉、Activity在內存緊張時被回收等情況下,Activity會被重新創建,此時,還在運行的AsyncTask會持有一個Activity的非法引用即之前的Activity實例。導致onPostExecute()沒有任何作用。

4、並行or串行
  • Android 1.6之前,默認採用串行執行任務;
  • Android 1.6~ 2.3 ,默認採用並行執行任務;
  • Android 3.0,默認採用串行執行任務,如果需要改爲並行,可以調用AsyncTask的executeOnExecutor()來執行任務即可。

5、AsyncTask的使用限制

  • AsyncTask的對象必須在主線程中創建;
  • execute 方法必須在UI線程調用;
  • 不要在程序中手動調用 onPreExecute、onPostExecute、 doInBackground、onProgressUpdate方法;
  • 一個AsyncTask對象只能調用一次excute()方法,執行一次,否則會報異常。

6、代碼實踐

模擬文件下載:
package com.example.ling.review.asynctask;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Toast;

import java.lang.ref.WeakReference;


public class AsyncTaskActivity extends AppCompatActivity {
    private DownLoadFileTask mTask = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 創建 DownLoadFileTask 實例
        mTask = new DownLoadFileTask(this);
        // 執行任務
        mTask.execute("參數1", "參數2", "參數3");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 取消 AsyncTask的任務
        mTask.cancel(true);
    }

    /**
     * 1、DownLoadFileTask 改爲靜態內部類,避免內存泄漏
     * 2、將Activity 包裝成弱引用,避免內存泄漏
     */
    public static class DownLoadFileTask extends AsyncTask<String, Integer, String> {
        private WeakReference<AsyncTaskActivity> mWeakReference = null;
        private ProgressDialog mProgressDialog = null;
        private Context mContext = null;

        public DownLoadFileTask(AsyncTaskActivity activity) {
            mWeakReference = new WeakReference<>(activity);
        }

        /**
         * 運行在主線程,執行後臺任務之前調用,通常用來做一些準備操作
         */
        @Override
        protected void onPreExecute() {
            mContext = mWeakReference.get();
            if (mContext != null) {
                mProgressDialog = new ProgressDialog(mContext);
                mProgressDialog.setCancelable(false);
                mProgressDialog.setTitle("任務正在執行中");
                mProgressDialog.setMessage("任務正在執行中,敬請期待...");
                mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                mProgressDialog.setMax(200);
                mProgressDialog.show();
            }
        }

        /**
         * 運行在線程池中,執行後臺耗時操作
         *
         * @param strings 參數
         * @return 結果
         */
        @Override
        protected String doInBackground(String... strings) {
            // 打印 mTask.execute();傳遞的參數
            StringBuilder builder = new StringBuilder();
            for (String string : strings) {
                builder.append(string).append(",");
            }
            Log.d("doInBackground", builder.toString());

            // 模擬下載
            int progress = 0;
            while (progress < 200) {
                try {
                    Thread.sleep(1000);   // 模擬耗時操作
                    progress += 10;
                    publishProgress(progress);// 更新進度,該方法調用後會觸發 onProgressUpdate方法
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            publishProgress(progress);
            String msg = "文件下載成功!";
            return msg;
        }

        /**
         * 運行在主線程,用於更新進度,publishProgress方法執行後,會觸發該方法
         *
         * @param values 進度值
         */
        @Override
        protected void onProgressUpdate(Integer... values) {
            if (mProgressDialog != null) {
                mProgressDialog.setProgress(values[0]);
            }
        }

        /**
         * 運行在主線程,後臺任務執行完成後,將返回值傳給該方法
         *
         * @param s 返回的結果
         */
        @Override
        protected void onPostExecute(String s) {
            if (mContext != null) {
                mProgressDialog.dismiss();
                Toast.makeText(mContext, s, Toast.LENGTH_SHORT).show();
            }
        }
    }
}
模擬文件下載:運行結果:

1、打印參數日誌:
01-28 10:25:56.385 5019-5089/com.example.ling.review D/doInBackground: 參數1,參數2,參數3,

2、運行界面效果

asyncTask

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章