Android網絡編程(四) 之 HttpClient與HttpURLConnection

Android本身提供了Apache 的 HttpClient 和 Java 的HttpURLConnection來進行網絡請求通信。它們都支持以流的方式進行網絡通信,並且都支持https。

1 HttpClient

HttpClient的優勢在於處理一些可能需要用戶登錄而且具有相應的權限纔可訪問該頁面。例如需要涉及Session、Cookie的處理時,就要使用HttpClient。它的實現類有DefaultHttpClientAndroidHttpClient。它們都擁有非常多的API供開發者調用,但是,在Android 6.0 SDK版本已經將HttpClient類庫移除了,如果想繼續使用它,可以在相應的module下的build.gradle中加入:

android {
       useLibrary 'org.apache.http.legacy'
}

使用示例:

/**
     * HttpClient的Get請求
     * @param url 請求的URL
     * @return
     */
    public static String httpClientGet(String url) {
        InputStream inStream = null;
        HttpClient httpclient = null;
        try {
            httpclient = new DefaultHttpClient();
            HttpResponse response = httpclient.execute(new HttpGet(url));
            inStream = response.getEntity().getContent();

            String result = inputStreamToString(inStream);
            return result;

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (inStream != null) {
                    inStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            httpclient.getConnectionManager().shutdown();
        }
        return null;
    }

    /**
     * HttpClient的Post請求
     * @param url 請求的URL
     * @param nameValuePairs 請求參數,值的添加如:nameValuePairs.add(new BasicNameValuePair("id", "12345"));
     * @return
     */
    public static String httpClientPost(String url, List<NameValuePair> nameValuePairs) {
        InputStream inStream = null;
        HttpClient httpclient = null;

        try {
            httpclient = new DefaultHttpClient();

            HttpPost httppost = new HttpPost(url);
            httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs ,"UTF-8"));
            HttpResponse response = httpclient.execute(httppost);
            inStream = response.getEntity().getContent();

            String result = inputStreamToString(inStream);
            return result;

        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (inStream != null) {
                    inStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            httpclient.getConnectionManager().shutdown();
        }
        return null;
    }

    /**
     * 將InputStream 格式轉化爲StringBuilder 格式
     * @param is
     * @return
     */
    private static String inputStreamToString(InputStream is) {
        String line = "";
        StringBuilder sb = new StringBuilder();
        try {
            BufferedReader rd = new BufferedReader(new InputStreamReader(is));
            while ((line = rd.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sb.toString();
// 或
//        Scanner scanner = new Scanner(is).useDelimiter("\\A");
//        return scanner.hasNext() ? scanner.next() : "";
    }

2 HttpURLConnection

如果在一般的網絡請求情況下,只是需要簡單的網絡請求或表單提交請求,HttpURLConnection則是最佳的選擇。它的API簡單,體積較小。壓縮和緩存機制可以有效地減少網絡訪問的流量,在提升速度和省電方面也起到了較大的作用。

不過你應該也要知道的是在過去Android2.2版本及之前,HttpURLConnection一直存在一些令人太麻煩的bug,比如對一個可讀的InputStream調用close()方法時,就有可能導致連接池失敗,所以往往那時要都禁用連接池功能。不過,那也是過去的往事了。

在Android2.3版本中也使得該BUG修復。並加入了響應壓縮,它會自動在每個發出的請求中加入Accept-Encoding: gzip報頭,並處理相應的返回結果;增加了https方面的優化,使用了SNI(Server Name Indication)的方式進行連接,使得多個HTTPS主機可以共享同一個IP地址;增加了若連接失敗,會自動去嘗試重連機制;在Android 4.0版本中還加入了一些響應的緩存機制等。

正如在Android 6.0版本後官方將HttpClient移除也是建議我們在開中發使用HttpURLConnection,而且目前手機分佈來看也不必再去對Android2.3之前的古董手機做適配了。

使用示例:

/**
     * HttpURLConnection的Get請求
     * @param urlStr
     * @return
     */
    public static String httpURLConnectionGet(String urlStr) {
        InputStream inStream = null;

        HttpURLConnection conn = null;
        try {
            URL url = new URL(urlStr);
            conn = (HttpURLConnection)url.openConnection();
//            conn.setConnectTimeout(timeOut);
//            conn.setReadTimeout(readTimeout);
            conn.setRequestMethod("GET");

            if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
                return null;
            }
            inStream = conn.getInputStream();

            String result = inputStreamToString(inStream);
            return result;

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (inStream != null) {
                    inStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (conn != null) {
                conn.disconnect();
            }
        }
        return null;
    }

    public static String HttpURLConnectionPost(String urlStr, String params) {
        HttpURLConnection conn = null;
        InputStream inStream = null;
        PrintWriter printWriter = null;
        try {
            URL url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            conn.setDoInput(true);
            conn.setDoOutput(true);                 // 是否輸入參數
            //conn.setConnectTimeout(timeOut);      // 連接超時 單位毫秒
            //conn.setReadTimeout(readTimeout);     // 讀取超時 單位毫秒
            conn.setUseCaches(false);               // Post 請求不能使用緩存

            // 第1種方式:使用直接輸出流的方式(已知輸出流的長度):
            // conn.setFixedLengthStreamingMode(輸出流的固定長度);

            // 第2種方式:使用直接輸出流的方式(未知輸出流的長度):
            conn.setChunkedStreamingMode(5);        // 5 爲塊的大小

            // 第3種方式:本地緩存後一次性輸出:
            // 兩個函數都不指定

            conn.setRequestMethod("POST");

            // application/x-www-form-urlencoded是表單數據;application/x-javascript是json對象;application/x-javascript text/xml是xml數據
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"); 
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("Content-Length", String.valueOf(params.length()));

            //PrintWriter 是文本。也就是unicode編碼格式的,當然也包括漢字。
            printWriter = new PrintWriter(conn.getOutputStream());
            printWriter.write(params);
            printWriter.flush();

            // OutputStream 接受的是bytes
            // byte[] data = params.getBytes("UTF-8");
            // OutputStream outputStream = conn.getOutputStream();
            // outputStream.write(data);
            // outputStream.flush();

            //DataOutputStream 是OutputStream的一個實用類,寫byte,寫String都可以
            // DataOutputStream dataOutputStream = new DataOutputStream(conn.getOutputStream());
            // dataOutputStream.writeBytes(params);
            // dataOutputStream.flush();

            if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){
                inStream = new BufferedInputStream(conn.getInputStream());
            } else {
                inStream = new BufferedInputStream(conn.getErrorStream());
            }

            String result = inputStreamToString(inStream);
            return result;

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
            if (printWriter != null) {
                printWriter.close();
            }
            try {
                if (inStream != null) {
                    inStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

 

下載文件示例:

public static boolean downloadZip(Context ctx, String urlStr) {
    InputStream is = null;
    FileOutputStream fos = null;
    boolean bRet = false;
    HttpURLConnection conn = null;
    try {
        File zipFile = getDownloadFile(ctx);  // 例如:/data/data/com.zyx.demo/mydownload/xx.zip
        URL url = new URL(urlStr);
        conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setReadTimeout(5000);
        conn.setConnectTimeout(5000);

        if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
            return false;
        }

        is = conn.getInputStream();
        fos = new FileOutputStream(zipFile);

        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = is.read(buffer)) != -1) {
            fos.write(buffer, 0, len);
        }
        bRet = true;
    } catch (Exception e) {
    } finally {
        try {
            if (is != null) {
                is.close();
            }
            if (fos != null) {
                fos.close();
            }
            if (conn != null) {
                conn.disconnect();
            }
        } catch (Exception e) {
        }
    }
    return bRet;
}

public static File getDownloadFile(Context ctx) {
    try {
        String dexDir = ctx.getDir("mydownload", Context.MODE_PRIVATE).getAbsolutePath();
        String path = dexDir + File.separator + "xx.zip";
        return new File(path);
    } catch (Exception e) {
    }
    return null;
}

 

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