1. 程式人生 > >AsyncTask解析(下)——實現自定義AsyncTask網路傳輸工具類封裝

AsyncTask解析(下)——實現自定義AsyncTask網路傳輸工具類封裝

在上文: AsyncTask解析(上)——原理分析與超簡單demo實現中已經對AsyncTask的實現原理以及原始碼流程進行了一定的分析,相信大家已經基本熟悉了AsyncTask內部實現網路傳輸的呼叫順序以及過程細節,最後還寫出了一個比較簡單的Demo實踐,十分簡單易懂相信大家都能很快掌握。

然而那個Demo還是太粗製濫造了,功能太缺乏,很多需要傳入的引數也沒有寫到構參裡直接給寫死了..

並且在真正的專案實踐中,光使用這個簡單的Demo是遠遠不夠的,我們需要對它進行更好的封裝,擴充套件它的功能,才能更好地為我們的專案服務。

所以,本文的核心重點是如何去封裝出一個AsyncTask工具類,以及如何讓

AsyncTask變得簡單易用。

整體框架的繼承關係如下圖所示:


理清一下思路,整體框架應用觀察者模式,可以細分為以下幾個步驟:

1、實現一個抽象類UrlAsyNet繼承AsyncTask<String,Integer,T>(這裡第三個引數設定為T是為了適配不同的傳輸型別)

這裡為什麼不用介面呢?因為介面的方法是不能有具體的實現的,但是在該方法中需要進行初始化的工作,所以這裡使用了抽象類來實現。

/**
 *   Created by nangua on 2016/4/26.
 *   Params 啟動任務執行的輸入引數,這裡是URL所以用String
 *   Progress 後臺任務執行的百分比。
 *   Result 後臺執行任務最終返回的結果,比如String。
 */
public class UrlAsyNet<T> extends AsyncTask<String,Integer,T> {
    /**
     * 全部引數構造方法
     * @param apikey
     * @param httpArg
     * @param httpUrl
     * @param method
     * @param onNetStateChangedListener
     * @param type
     */
    public UrlAsyNet(String apikey, String httpArg, String httpUrl, NetMethod method, OnNetStateChangedListener<T> onNetStateChangedListener, ParamType type) {
        this.apikey = apikey;
        this.httpArg = httpArg;
        this.httpUrl = httpUrl;
        this.method = method;
        this.onNetStateChangedListener = onNetStateChangedListener;
        this.type = type;
    }
 
    /**
     * 傳入URL
     * @param httpUrl
     */
    public UrlAsyNet(String httpUrl,String apikey,String httpArg) {
        this.httpUrl = httpUrl;
        this.apikey = apikey;
        this.httpArg = httpArg;
    }
 
    //新增列舉型別
    public enum NetMethod{
        GET,POST
    }
 
    /**
     * 引數型別。分為:JSONorXML檔案。鍵值對,無參
     */
    public enum ParamType{
        JSON_OR_XML_FILE
        ,KEY_VALUE_PAIR,
        NO_PARAM
    }
 
    /**
     * 網路狀態改變時候的監聽器
     * @param <T>
     */
    public interface OnNetStateChangedListener<T> {
        /**
         * 訪問網路之前
         */
        public void beforeAccessNet();
 
        /**
         * 訪問網路成功獲取資料之後
         *
         * @param result
         */
        public void afterAccessNet(T result);
 
        /**
         * 出現了錯誤的時候
         */
        public void whenException();
 
        /**
         * 執行進度
         * @param progress
         */
        public void onProgress(Integer progress);
    }
 
    //設定監聽器回撥
 
    public OnNetStateChangedListener<T> getOnNetStateChangedListener() {
        return onNetStateChangedListener;
    }
 
    //設定網路監聽器
    public void setOnNetStateChangedListener(OnNetStateChangedListener<T> onNetStateChangedListener) {
        this.onNetStateChangedListener = onNetStateChangedListener;
    }
 
    //網路監聽器例項
    OnNetStateChangedListener<T> onNetStateChangedListener;
 
    //在四個回撥方法中呼叫網路監聽器的方法以實現回撥
    @Override
    protected void onCancelled() {
        if (onNetStateChangedListener!=null){
            onNetStateChangedListener.whenException();
        }
    }
 
    @Override
    protected void onPostExecute(T t) {
        if (onNetStateChangedListener!=null){
            onNetStateChangedListener.afterAccessNet(t);
        }
    }
 
    @Override
    protected void onPreExecute() {
        if (onNetStateChangedListener!=null){
            onNetStateChangedListener.beforeAccessNet();
        }
    }
 
 
    @Override
    protected void onProgressUpdate(Integer... values) {
        if (onNetStateChangedListener!=null){
            if (values.length>1) {
                onNetStateChangedListener.onProgress(values[0]);
            }
        }
    }
 
    //使用HttpURLConnection需要用到的httpUrl
    String httpUrl ;
    //使用HttpURLConnection需要用到的httpArg
    String httpArg ;
    //連線百度API需要的APIKEY
    String apikey;
    //得到的引數型別
    ParamType type;
    //網路請求引數(GET或POST)
    NetMethod method;
    //資料
    String jsonOrXmlFile;
    //鍵值對
    HashMap<String, Object> keyValuePair;
 
 
    public String getHttpUrl() {
        return httpUrl;
    }
 
    public void setHttpUrl(String httpUrl) {
        this.httpUrl = httpUrl;
    }
 
    public String getApikey() {
        return apikey;
    }
 
    public void setApikey(String apikey) {
        this.apikey = apikey;
    }
 
    public String getHttpArg() {
        return httpArg;
    }
 
    public void setHttpArg(String httpArg) {
        this.httpArg = httpArg;
    }
 
    public ParamType getType() {
        return type;
    }
 
    public void setType(ParamType type) {
        this.type = type;
    }
 
 
    @Override
    protected T doInBackground(String... params) {
        return null;
    }
 
    /**
     * 執行
     */
    public void execute(){
        this.execute(new String[]{});
    }
}

2、在抽象類裡編寫一個網路監聽器介面。然後在需要使用到的地方(比如在MainActivity裡需要使用,就在MainActivity裡寫一個實現這個介面的內部類,從而在這個內部類裡實現隨著網路狀態的改變改變對UI的操作)

那麼問題來了:這裡為什麼不把元件當做引數傳進去呢?比如在上文中的Demo是把TextViewProgressBar傳進去的,那麼如果你要傳入的是一個CustView呢?這樣就得重新修改寫好的程式碼,拆輪子,違背了程式的可擴充套件性。所以更好的辦法是提供一個可實現的網路監聽介面,在接口裡進行更新UI操作。

/**
     * 網路狀態改變時候的監聽器
     * @param <T>
     */
    public interface OnNetStateChangedListener<T> {
        /**
         * 訪問網路之前
         */
        public void beforeAccessNet();

        /**
         * 訪問網路成功獲取資料之後
         *
         * @param result
         */
        public void afterAccessNet(T result);

        /**
         * 出現了錯誤的時候
         */
        public void whenException();

        /**
         * 執行進度
         * @param progress
         */
        public void onProgress(Integer progress);
    }
網路監聽器的程式碼上文已經出現了,這裡單獨列出來一下。

3、編寫具體的工具類UrlNormalAsyNet,實現對資料的接受(暫時沒有寫JSON和XML的解析):

/**
 * Created by nangua on 2016/4/26.
 */
public class UrlNormalAsyNet extends UrlAsyNet<String>{
    /**
     * 請求方法POST和get
     */
    AsyNet.NetMethod method;

    public UrlNormalAsyNet(String apikey, String httpArg, String httpUrl, NetMethod method, OnNetStateChangedListener<String> onNetStateChangedListener, ParamType type) {
        super(apikey, httpArg, httpUrl, method, onNetStateChangedListener, type);
    }

    public UrlNormalAsyNet(String httpUrl, String apikey, String httpArg) {
        super(httpUrl, apikey, httpArg);
        this.httpUrl = httpUrl;
        this.apikey = apikey;
        this.httpArg = httpArg;
    }

    @Override
    protected String doInBackground(String... params) {
        BufferedReader reader = null;
        String result = null;
        StringBuffer sbf = new StringBuffer();
        httpUrl = httpUrl + "?" + httpArg;

        try {
            URL url = new URL(httpUrl);
            HttpURLConnection connection = (HttpURLConnection) url
                    .openConnection();
            connection.setRequestMethod("GET");
            connection.setRequestProperty("apikey",  apikey);
            connection.connect();
            InputStream is = connection.getInputStream();
            reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
            String strRead = null;
            while ((strRead = reader.readLine()) != null) {
                sbf.append(strRead);
                sbf.append("\r\n");
            }
            reader.close();
            result = sbf.toString();
            if (result != null) {
                publishProgress(100);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}

執行截圖:


本文暫時更新到這裡,以後有時間再繼續更新

目標要實現的工具類有三個:UrlFileAsyNet(處理檔案網路傳輸資訊),UrlImageAsyNet(處理圖片傳輸資訊),UrlNormalAsyNet(處理JSONXML,或String格式網路傳輸資訊)

以下是大神同學Dikaros寫的完整AsyncTask工具包下載地址:https://github.com/Dikaros/AsyNet 

QAQ(づ ̄ 3 ̄)づ求贊求關注!