1. 程式人生 > >Android 自定義網路載入工具類 HttpURLConnectionUtils

Android 自定義網路載入工具類 HttpURLConnectionUtils

程式碼已經上傳到github,歡迎Star。

一個自己封裝的用HttpUrlConnection請求的網路工具類,但只適合新手研究或者做些小demo用下, 畢竟現在對於Android開發的網路框架有很多,而且很好很強大。

  • 目前支援的功能:

1、GET,POST請求

2、支援返回String,Byte[]陣列,以及自定義的Model類

3、請求的回撥已處理過,現在的回撥在UI執行緒,所以可以直接更新UI

同樣的,如果寫demo啥的,可以按照以下方式依賴進專案:

allprojects {
    repositories {
        ...
maven { url 'https://jitpack.io' } } } dependencies { compile 'com.github.MZCretin:HttpUrlConnectionUtilDemo:v1.0' }

後面如果有需要,我會加上下載檔案的方法。

如果有啥問題,歡迎交流:

792075058

[email protected]

正文

  • 最近吃膩了外賣,想著自己做飯吃,所以就自己做了一個菜譜的小軟體,從api服務上找了一個菜譜的介面就開始做了,在做的過程中,需要請求一個介面,來獲取菜譜資訊,於是就想到Android現在很火的各種網路框架。。。在選擇的時候就犯難了,我就寫個軟體自己用,就簡單的請求一個介面,有必要用這麼重的框架麼。然後就開始了主題所說的自定義一個簡單的網路載入工具類。

  • 我這邊只是做了一個簡單的封裝。

  • 首先:定義一個 static ExecutorService threadPool = Executors.newCachedThreadPool(),來建立一個可根據需要建立新執行緒的執行緒池,但是在以前構造的執行緒可用時將重用它們。因為不能在主執行緒請求網路,所以用這個執行緒池來裝載我們用於進行網路請求的執行緒,定義一個static Gson gson = new Gson();用來將請求的json資料轉換成對應的Model物件。

  • 然後:定義第一個方法,也就是返回字串的方法。在這個方法裡,上面有關HttpURLConnection的操作都是一樣的,不一樣的是最後對流的處理,這個方法要求返回的是字串,所以我們在獲取到流的時候將其轉化成我們需要的字串,再通過回撥給呼叫者,其他goGet方法也一樣,如果需要byte陣列,我們就返回byte陣列,如果需要物件,我們就先轉成String字串,然後通過gson將json字串轉換成對應的物件返回即可。(具體請看原始碼,下面會貼出原始碼)

doGet方法

 /**
     * GET方法 返回資料會解析成字串String
     * @param context 上下文
     * @param urlString 請求的url
     * @param listener 回撥監聽
     */
    public static void doGet(final Context context, final String urlString,
                             final HttpCallbackStringListener listener) {
        // 因為網路請求是耗時操作,所以需要另外開啟一個執行緒來執行該任務。
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                URL url;
                HttpURLConnection httpURLConnection = null;
                try {
                    // 根據URL地址建立URL物件
                    url = new URL(urlString);
                    // 獲取HttpURLConnection物件
                    httpURLConnection = ( HttpURLConnection ) url.openConnection();
                    // 設定請求方式,預設為GET
                    httpURLConnection.setRequestMethod("GET");
                    // 設定連線超時
                    httpURLConnection.setConnectTimeout(5000);
                    // 設定讀取超時
                    httpURLConnection.setReadTimeout(8000);
                    // 響應碼為200表示成功,否則失敗。
                    if ( httpURLConnection.getResponseCode() == 200 ) {
                        // 獲取網路的輸入流
                        InputStream is = httpURLConnection.getInputStream();
                        BufferedReader bf = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                        //最好在將位元組流轉換為字元流的時候 進行轉碼
                        StringBuffer buffer = new StringBuffer();
                        String line = "";
                        while ( (line = bf.readLine()) != null ) {
                            buffer.append(line);
                        }
                        bf.close();
                        is.close();
                        new ResponseCall(context, listener).doSuccess(buffer.toString());
                    } else {
                        new ResponseCall(context, listener).doFail(
                                new NetworkErrorException("response err code:" +
                                        httpURLConnection.getResponseCode()));
                    }
                } catch ( MalformedURLException e ) {
                    if ( listener != null ) {
                        // 回撥onError()方法
                        new ResponseCall(context, listener).doFail(e);
                    }
                } catch ( IOException e ) {
                    if ( listener != null ) {
                        // 回撥onError()方法
                        new ResponseCall(context, listener).doFail(e);
                    }
                } finally {
                    if ( httpURLConnection != null ) {
                        // 釋放資源
                        httpURLConnection.disconnect();
                    }
                }
            }
        });
    }

上面講了doGet方法的實現,其實doPost方法的實現除了需要帶上引數列表之外其他都是是一樣的。對於引數的處理,在我的開發經歷中,引數都是放在Map容器中傳遞的,所以在這裡也就使用的這種方式,對於傳進來的引數,我們需要進行處理下,其實也就是字串的拼接,拼接成HttpURLConnection能夠識別的形式。下面的程式碼進行了引數的組織:

final StringBuffer out = new StringBuffer();
        // 組織請求引數
        for (String key : params.keySet()) {
            if(out.length()!=0){
                out.append("&");
            }
            out.append(key).append("=").append(params.get(key));
        }

拼接好引數列表之後,我們通過httpURLConnection.getOutputStream()獲取到PrintWriter,然後寫入我們的引數資訊即可。其他的操作跟get請求是一樣的。

PrintWriter printWriter = new PrintWriter(httpURLConnection.getOutputStream());
// 傳送請求引數
printWriter.write(out.toString());
// flush輸出流的緩衝
printWriter.flush();
printWriter.close();

doPost方法

/**
     * POST方法 返回資料會解析成字串 String
     * @param context 上下文
     * @param urlString 請求的路徑
     * @param listener  回撥監聽
     * @param params 引數列表
     */
    public static void doPost(final Context context,
                              final String urlString, final HttpCallbackStringListener listener,
                              final Map<String, Object> params) {
        final StringBuffer out = new StringBuffer();
        // 組織請求引數
        for (String key : params.keySet()) {
            if(out.length()!=0){
                out.append("&");
            }
            out.append(key).append("=").append(params.get(key));
        }
        // 因為網路請求是耗時操作,所以需要另外開啟一個執行緒來執行該任務。
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                URL url;
                HttpURLConnection httpURLConnection = null;
                try {
                    url = new URL(urlString);
                    httpURLConnection = ( HttpURLConnection ) url.openConnection();
                    httpURLConnection.setRequestProperty("accept", "*/*");
                    httpURLConnection.setRequestProperty("connection", "Keep-Alive");
                    httpURLConnection.setRequestProperty("Content-Length", String
                            .valueOf(out.length()));
                    httpURLConnection.setRequestMethod("POST");

                    httpURLConnection.setConnectTimeout(5000);
                    httpURLConnection.setReadTimeout(8000);

                    // 設定執行輸入
                    httpURLConnection.setDoInput(true);
                    // 設定執行輸出
                    httpURLConnection.setDoOutput(true);

                    PrintWriter printWriter = new PrintWriter(httpURLConnection.getOutputStream());
                    // 傳送請求引數
                    printWriter.write(out.toString());
                    // flush輸出流的緩衝
                    printWriter.flush();
                    printWriter.close();

                    if ( httpURLConnection.getResponseCode() == 200 ) {
                        // 獲取網路的輸入流
                        InputStream is = httpURLConnection.getInputStream();
                        BufferedReader bf = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                        //最好在將位元組流轉換為字元流的時候 進行轉碼
                        StringBuffer buffer = new StringBuffer();
                        String line = "";
                        while ( (line = bf.readLine()) != null ) {
                            buffer.append(line);
                        }
                        bf.close();
                        is.close();
                        new ResponseCall(context, listener).doSuccess(buffer.toString());
                    } else {
                        new ResponseCall(context, listener).doFail(
                                new NetworkErrorException("response err code:" +
                                        httpURLConnection.getResponseCode()));
                    }
                } catch ( MalformedURLException e ) {
                    if ( listener != null ) {
                        // 回撥onError()方法
                        new ResponseCall(context, listener).doFail(e);
                    }
                } catch ( IOException e ) {
                    if ( listener != null ) {
                        // 回撥onError()方法
                        new ResponseCall(context, listener).doFail(e);
                    }
                } finally {
                    if ( httpURLConnection != null ) {
                        // 最後記得關閉連線
                        httpURLConnection.disconnect();
                    }
                }
            }
        });
    }

在上面的程式碼中,在請求的最後,我們會看到一個 new ResponseCall(context, listener).doSuccess(buffer.toString());這個是用來幹嘛的呢?其實這個是用來進行子執行緒和主執行緒的資料交換的,定義一個Handler,不過Handler是通過looper來建立的,looper是通過傳進來的上下文Context來獲取主執行緒的looper,然後次Handler就是位於主執行緒的。當請求結束後,如果請求成功,則呼叫doSuccess(T response)方法,給Handler傳送訊息,訊息的what值為0,訊息的內容是請求的結果;請求失敗或錯誤的時候,呼叫doFail(Exception e)方法,給Handler傳送訊息,訊息的what值為1,訊息的內容是請求失敗的異常資訊。當Handler收到訊息之後,直接呼叫listener的回撥方法,就可以一方面把資料回調回去,另一方面,回撥也是處於主執行緒也就是UI執行緒了,這樣呼叫者就可以直接在回撥方法中更新UI了。

ResponseCall.java

/**
 * Created by cretin on 2017/3/20.
 */

public class ResponseCall<T> {
    //用於在子執行緒和主執行緒的資料交換
    Handler mHandler;

    public ResponseCall(Context context, final HttpCallbackModelListener listener) {
        Looper looper = context.getMainLooper();
        mHandler = new Handler(looper) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if ( msg.what == 0 ) {
                    //成功
                    listener.onFinish(msg.obj);
                } else if ( msg.what == 1 ) {
                    //失敗
                    listener.onError(( Exception ) msg.obj);
                }
            }
        };
    }

    public ResponseCall(Context context, final HttpCallbackBytesListener listener) {
        Looper looper = context.getMainLooper();
        mHandler = new Handler(looper) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if ( msg.what == 0 ) {
                    //成功
                    listener.onFinish(( byte[] ) msg.obj);
                } else if ( msg.what == 1 ) {
                    //失敗
                    listener.onError(( Exception ) msg.obj);
                }
            }
        };
    }

    public ResponseCall(Context context, final HttpCallbackStringListener listener) {
        Looper looper = context.getMainLooper();
        mHandler = new Handler(looper) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if ( msg.what == 0 ) {
                    //成功
                    listener.onFinish(msg.obj.toString());
                } else if ( msg.what == 1 ) {
                    //失敗
                    listener.onError(( Exception ) msg.obj);
                }
            }
        };
    }

    public void doSuccess(T response) {
        Message message = Message.obtain();
        message.obj = response;
        message.what = 0;
        mHandler.sendMessage(message);
    }

    public void doFail(Exception e) {
        Message message = Message.obtain();
        message.obj = e;
        message.what = 1;
        mHandler.sendMessage(message);
    }
}

下面是實際中的呼叫例項:

MainActivity.java

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.TextView;

import com.cretin.www.httpurlconnectionutil.HttpUtils;
import com.cretin.www.httpurlconnectionutil.callback.HttpCallbackBytesListener;
import com.cretin.www.httpurlconnectionutil.callback.HttpCallbackModelListener;
import com.cretin.www.httpurlconnectionutil.callback.HttpCallbackStringListener;
import com.cretin.www.httpurlconnectionutildemo.model.ResponseModel;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final TextView tvContent = ( TextView ) findViewById(R.id.tv_content);

        //測試GET請求

        //返回字串
        try {
            HttpUtils.doGet(this, "http://caipu.yjghost.com/index.php/query/read?menu=" + URLEncoder.encode("土豆", "UTF-8") + "&rn=15&start=1", new HttpCallbackStringListener() {

                @Override
                public void onFinish(String response) {
                    tvContent.setText(response);
                }

                @Override
                public void onError(Exception e) {
                    tvContent.setText(e.toString());
                }
            });
        } catch ( UnsupportedEncodingException e ) {
            e.printStackTrace();
        }

        //返回byte陣列
        try {
            HttpUtils.doGet(this, "http://caipu.yjghost.com/index.php/query/read?menu=" + URLEncoder.encode("土豆", "UTF-8") + "&rn=15&start=1", new HttpCallbackBytesListener() {
                @Override
                public void onFinish(byte[] response) {
                    Log.e("HHHHHHH", "GET 方法:" + new String(response));
                }

                @Override
                public void onError(Exception e) {
                    Log.e("HHHHHHH", "doGet onError:" + e.toString());
                }
            });
        } catch ( UnsupportedEncodingException e ) {
            e.printStackTrace();
        }

        //返回物件
        try {
            HttpUtils.doGet(this, "http://caipu.yjghost.com/index.php/query/read?menu=" +
                            URLEncoder.encode("土豆", "UTF-8") + "&rn=15&start=1",
                    new HttpCallbackModelListener<ResponseModel>() {
                        @Override
                        public void onFinish(ResponseModel response) {
                            Log.e("HHHHHHH", "GET 方法:" + response.getResult().getTotalNum());
                        }

                        @Override
                        public void onError(Exception e) {
                            Log.e("HHHHHHH", "doGet onError:" + e.toString());
                        }
                    }, ResponseModel.class);
        } catch ( UnsupportedEncodingException e ) {
            e.printStackTrace();
        }

        //測試POST請求

        //引數列表
        Map<String, Object> map = new HashMap<>();
        map.put("productFirstType", "1");
        map.put("loanRange", "1");
        map.put("type", "hot");
        map.put("page", "1");
        map.put("timeRange", "1");

        //返回String
        HttpUtils.doPost(this, "http://101.201.31.212:8016/product/listProduct", new HttpCallbackStringListener() {
            @Override
            public void onFinish(String response) {
                Log.e("HHHHHHH", "POST 方法:" + response);
            }

            @Override
            public void onError(Exception e) {
                Log.e("HHHHHHH", "doPost onError:" + e.toString());
            }
        }, map);
        //返回byte陣列
        HttpUtils.doPost(this, "http://101.201.31.212:8016/product/listProduct", new HttpCallbackBytesListener() {
            @Override
            public void onFinish(byte[] response) {
                Log.e("HHHHHHH", "POST 方法:" + new String(response));
            }

            @Override
            public void onError(Exception e) {
                Log.e("HHHHHHH", "doPost onError:" + e.toString());
            }
        }, map);
        //返回物件
        HttpUtils.doPost(this, "http://101.201.31.212:8016/product/listProduct", new HttpCallbackModelListener<ResponseModel>() {
            @Override
            public void onFinish(ResponseModel response) {
                Log.e("HHHHHHH", "POST 方法:" + response.getResult().getTotalNum());
            }

            @Override
            public void onError(Exception e) {
                Log.e("HHHHHHH", "doPost onError:" + e.toString());
            }
        }, map, ResponseModel.class);
    }
}

下面貼出整個工具類的程式碼:

import android.accounts.NetworkErrorException;
import android.content.Context;

import com.cretin.www.httpurlconnectionutil.callback.HttpCallbackBytesListener;
import com.cretin.www.httpurlconnectionutil.callback.HttpCallbackModelListener;
import com.cretin.www.httpurlconnectionutil.callback.HttpCallbackStringListener;
import com.cretin.www.httpurlconnectionutil.response.ResponseCall;
import com.google.gson.Gson;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 *  Created by cretin on 2017/3/22.
 *  HttpURLConnection 網路請求工具類
 *
 *  資料的請求都是基於HttpURLConnection的 請求成功與失敗的回撥都是在主執行緒
 *  可以直接更新UI
 */
public class HttpUtils {
    static ExecutorService threadPool = Executors.newCachedThreadPool();
    static Gson gson = new Gson();

    /**
     * GET方法 返回資料會解析成字串String
     * @param context 上下文
     * @param urlString 請求的url
     * @param listener 回撥監聽
     */
    public static void doGet(final Context context, final String urlString,
                             final HttpCallbackStringListener listener) {
        // 因為網路請求是耗時操作,所以需要另外開啟一個執行緒來執行該任務。
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                URL url;
                HttpURLConnection httpURLConnection = null;
                try {
                    // 根據URL地址建立URL物件
                    url = new URL(urlString);
                    // 獲取HttpURLConnection物件
                    httpURLConnection = ( HttpURLConnection ) url.openConnection();
                    // 設定請求方式,預設為GET
                    httpURLConnection.setRequestMethod("GET");
                    // 設定連線超時
                    httpURLConnection.setConnectTimeout(5000);
                    // 設定讀取超時
                    httpURLConnection.setReadTimeout(8000);
                    // 響應碼為200表示成功,否則失敗。
                    if ( httpURLConnection.getResponseCode() == 200 ) {
                        // 獲取網路的輸入流
                        InputStream is = httpURLConnection.getInputStream();
                        BufferedReader bf = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                        //最好在將位元組流轉換為字元流的時候 進行轉碼
                        StringBuffer buffer = new StringBuffer();
                        String line = "";
                        while ( (line = bf.readLine()) != null ) {
                            buffer.append(line);
                        }
                        bf.close();
                        is.close();
                        new ResponseCall(context, listener).doSuccess(buffer.toString());
                    } else {
                        new ResponseCall(context, listener).doFail(
                                new NetworkErrorException("response err code:" +
                                        httpURLConnection.getResponseCode()));
                    }
                } catch ( MalformedURLException e ) {
                    if ( listener != null ) {
                        // 回撥onError()方法
                        new ResponseCall(context, listener).doFail(e);
                    }
                } catch ( IOException e ) {
                    if ( listener != null ) {
                        // 回撥onError()方法
                        new ResponseCall(context, listener).doFail(e);
                    }
                } finally {
                    if ( httpURLConnection != null ) {
                        // 釋放資源
                        httpURLConnection.disconnect();
                    }
                }
            }
        });
    }

    /**
     * GET方法 返回資料會解析成byte[]陣列
     * @param context 上下文
     * @param urlString 請求的url
     * @param listener 回撥監聽
     */
    public static void doGet(final Context context, final String urlString,
                             final HttpCallbackBytesListener listener) {
        // 因為網路請求是耗時操作,所以需要另外開啟一個執行緒來執行該任務。
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                URL url = null;
                HttpURLConnection httpURLConnection = null;
                try {
                    // 根據URL地址建立URL物件
                    url = new URL(urlString);
                    // 獲取HttpURLConnection物件
                    httpURLConnection = ( HttpURLConnection ) url.openConnection();
                    // 設定請求方式,預設為GET
                    httpURLConnection.setRequestMethod("GET");
                    // 設定連線超時
                    httpURLConnection.setConnectTimeout(5000);
                    // 設定讀取超時
                    httpURLConnection.setReadTimeout(8000);
                    // 響應碼為200表示成功,否則失敗。
                    if ( httpURLConnection.getResponseCode() != 200 ) {
                        new ResponseCall(context, listener).doFail(
                                new NetworkErrorException("response err code:" +
                                        httpURLConnection.getResponseCode()));
                    } else {
                        // 獲取網路的輸入流
                        InputStream is = httpURLConnection.getInputStream();
                        // 讀取輸入流中的資料
                        BufferedInputStream bis = new BufferedInputStream(is);
                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
                        byte[] bytes = new byte[1024];
                        int len = -1;
                        while ( (len = bis.read(bytes)) != -1 ) {
                            baos.write(bytes, 0, len);
                        }
                        bis.close();
                        is.close();
                        // 響應的資料
                        new ResponseCall(context, listener).doSuccess(baos.toByteArray());
                    }
                } catch ( MalformedURLException e ) {
                    if ( listener != null ) {
                        // 回撥onError()方法
                        new ResponseCall(context, listener).doFail(e);
                    }
                } catch ( IOException e ) {
                    if ( listener != null ) {
                        // 回撥onError()方法
                        new ResponseCall(context, listener).doFail(e);
                    }
                } finally {
                    if ( httpURLConnection != null ) {
                        // 釋放資源
                        httpURLConnection.disconnect();
                    }
                }
            }
        });
    }

    /**
     * GET方法 返回資料會解析成cls物件
     * @param context 上下文
     * @param urlString 請求路徑
     * @param listener 回撥監聽
     * @param cls 返回的物件
     * @param <T> 監聽的泛型
     */
    public static <T> void doGet(final Context context,
                                 final String urlString,
                                 final HttpCallbackModelListener listener, final Class<T> cls) {
        // 因為網路請求是耗時操作,所以需要另外開啟一個執行緒來執行該任務。
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                URL url;
                HttpURLConnection httpURLConnection = null;
                try {
                    // 根據URL地址建立URL物件
                    url = new URL(urlString);
                    // 獲取HttpURLConnection物件
                    httpURLConnection = ( HttpURLConnection ) url.openConnection();
                    // 設定請求方式,預設為GET
                    httpURLConnection.setRequestMethod("GET");
                    // 設定連線超時
                    httpURLConnection.setConnectTimeout(5000);
                    // 設定讀取超時
                    httpURLConnection.setReadTimeout(8000);
                    // 響應碼為200表示成功,否則失敗。
                    if ( httpURLConnection.getResponseCode() == 200 ) {
                        // 獲取網路的輸入流
                        InputStream is = httpURLConnection.getInputStream();
                        BufferedReader bf = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                        //最好在將位元組流轉換為字元流的時候 進行轉碼
                        StringBuffer buffer = new StringBuffer();
                        String line = "";
                        while ( (line = bf.readLine()) != null ) {
                            buffer.append(line);
                        }
                        bf.close();
                        is.close();
                        new ResponseCall(context, listener).doSuccess(gson.fromJson(buffer.toString(), cls));
                    } else {
                        if ( listener != null ) {
                            // 回撥onError()方法
                            new ResponseCall(context, listener).doFail(
                                    new NetworkErrorException("response err code:" +
                                            httpURLConnection.getResponseCode()));
                        }
                    }
                } catch ( MalformedURLException e ) {
                    if ( listener != null ) {
                        // 回撥onError()方法
                        new ResponseCall(context, listener).doFail(e);
                    }
                } catch ( IOException e ) {
                    if ( listener != null ) {
                        // 回撥onError()方法
                        new ResponseCall(context, listener).doFail(e);
                    }
                } finally {
                    if ( httpURLConnection != null ) {
                        // 釋放資源
                        httpURLConnection.disconnect();
                    }
                }
            }
        });
    }


    /**
     * POST方法 返回資料會解析成字串 String
     * @param context 上下文
     * @param urlString 請求的路徑
     * @param listener  回撥監聽
     * @param params 引數列表
     */
    public static void doPost(final Context context,
                              final String urlString, final HttpCallbackStringListener listener,
                              final Map<String, Object> params) {
        final StringBuffer out = new StringBuffer();
        // 組織請求引數
        for (String key : params.keySet()) {
            if(out.length()!=0){
                out.append("&");
            }
            out.append(key).append("=").append(params.get(key));
        }
        // 因為網路請求是耗時操作,所以需要另外開啟一個執行緒來執行該任務。
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                URL url;
                HttpURLConnection httpURLConnection = null;
                try {
                    url = new URL(urlString);
                    httpURLConnection = ( HttpURLConnection ) url.openConnection();
                    httpURLConnection.setRequestProperty("accept", "*/*");
                    httpURLConnection.setRequestProperty("connection", "Keep-Alive");
                    httpURLConnection.setRequestProperty("Content-Length", String
                            .valueOf(out.length()));
                    httpURLConnection.setRequestMethod("POST");

                    httpURLConnection.setConnectTimeout(5000);
                    httpURLConnection.setReadTimeout(8000);

                    // 設定執行輸入
                    httpURLConnection.setDoInput(true);
                    // 設定執行輸出
                    httpURLConnection.setDoOutput(true);

                    PrintWriter printWriter = new PrintWriter(httpURLConnection.getOutputStream());
                    // 傳送請求引數
                    printWriter.write(out.toString());
                    // flush輸出流的緩衝
                    printWriter.flush();
                    printWriter.close();

                    if ( httpURLConnection.getResponseCode() == 200 ) {
                        // 獲取網路的輸入流
                        InputStream is = httpURLConnection.getInputStream();
                        BufferedReader bf = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                        //最好在將位元組流轉換為字元流的時候 進行轉碼
                        StringBuffer buffer = new StringBuffer();
                        String line = "";
                        while ( (line = bf.readLine()) != null ) {
                            buffer.append(line);
                        }
                        bf.close();
                        is.close();
                        new ResponseCall(context, listener).doSuccess(buffer.toString());
                    } else {
                        new ResponseCall(context, listener).doFail(
                                new NetworkErrorException("response err code:" +
                                        httpURLConnection.getResponseCode()));
                    }
                } catch ( MalformedURLException e ) {
                    if ( listener != null ) {
                        // 回撥onError()方法
                        new ResponseCall(context, listener).doFail(e);
                    }
                } catch ( IOException e ) {
                    if ( listener != null ) {
                        // 回撥onError()方法
                        new ResponseCall(context, listener).doFail(e);
                    }
                } finally {
                    if ( httpURLConnection != null ) {
                        // 最後記得關閉連線
                        httpURLConnection.disconnect();
                    }
                }
            }
        });
    }


    /**
     * POST方法 返回資料會解析成Byte[]陣列
     * @param context 上下文
     * @param urlString 請求的路徑
     * @param listener  回撥監聽
     * @param params 引數列表
     */
    public static void doPost(final Context context,
                              final String urlString, final HttpCallbackBytesListener listener,
                              final Map<String, Object> params) {
        final StringBuffer out = new StringBuffer();
        // 組織請求引數
        for (String key : params.keySet()) {
            if(out.length()!=0){
                out.append("&");
            }
            out.append(key).append("=").append(params.get(key));
        }
        // 因為網路請求是耗時操作,所以需要另外開啟一個執行緒來執行該任務。
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                URL url;
                HttpURLConnection httpURLConnection = null;
                try {
                    url = new URL(urlString);
                    httpURLConnection = ( HttpURLConnection ) url.openConnection();
                    httpURLConnection.setRequestProperty("accept", "*/*");
                    httpURLConnection.setRequestProperty("connection", "Keep-Alive");
                    httpURLConnection.setRequestProperty("Content-Length", String
                            .valueOf(out.length()));
                    httpURLConnection.setRequestMethod("POST");

                    httpURLConnection.setConnectTimeout(5000);
                    httpURLConnection.setReadTimeout(8000);

                    // 設定執行輸入
                    httpURLConnection.setDoInput(true);
                    // 設定執行輸出
                    httpURLConnection.setDoOutput(true);

                    PrintWriter printWriter = new PrintWriter(httpURLConnection.getOutputStream());
                    // 傳送請求引數
                    printWriter.write(out.toString());
                    // flush輸出流的緩衝
                    printWriter.flush();
                    printWriter.close();

                    if ( httpURLConnection.getResponseCode() == 200 ) {
                        // 獲取網路的輸入流
                        InputStream is = httpURLConnection.getInputStream();
                        // 讀取輸入流中的資料
                        BufferedInputStream bis = new BufferedInputStream(is);
                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
                        byte[] bytes = new byte[1024];
                        int len = -1;
                        while ( (len = bis.read(bytes)) != -1 ) {
                            baos.write(bytes, 0, len);
                        }
                        bis.close();
                        is.close();
                        // 響應的資料
                        new ResponseCall(context, listener).doSuccess(baos.toByteArray());
                    } else {
                        new ResponseCall(context, listener).doFail(
                                new NetworkErrorException("response err code:" +
                                        httpURLConnection.getResponseCode()));
                    }
                } catch ( MalformedURLException e ) {
                    if ( listener != null ) {
                        // 回撥onError()方法
                        new ResponseCall(context, listener).doFail(e);
                    }
                } catch ( IOException e ) {
                    if ( listener != null ) {
                        // 回撥onError()方法
                        new ResponseCall(context, listener).doFail(e);
                    }
                } finally {
                    if ( httpURLConnection != null ) {
                        // 最後記得關閉連線
                        httpURLConnection.disconnect();
                    }
                }
            }
        });
    }


    /**
     * /**
     * POST方法 返回資料會解析成cls物件
     * @param context 上下文
     * @param urlString 請求的路徑
     * @param listener  回撥監聽
     * @param params 引數列表
     * @param cls 物件
     * @param <T> 監聽泛型
     */
    public static <T> void doPost(final Context context,
                                  final String urlString, final HttpCallbackModelListener listener,
                                  final Map<String, Object> params, final Class<T> cls) {
        final StringBuffer paramsStr = new StringBuffer();
        // 組織請求引數
        Iterator it = params.entrySet().iterator();
        while ( it.hasNext() ) {
            Map.Entry element = ( Map.Entry ) it.next();
            paramsStr.append(element.getKey());
            paramsStr.append("=");
            params