1. 程式人生 > >Android HttpClient HttpUrlConnection用法總結

Android HttpClient HttpUrlConnection用法總結

HttpClient

這個不用說了,Apache的API,但是不推薦使用了,在最新的api中甚至都把HttpClient去掉了。但是還是有必要掌握下HttpClient的用法的

GET方式

//先將引數放入List,再對引數進行URL編碼
List<BasicNameValuePair> params = new LinkedList<BasicNameValuePair>();
params.add(new BasicNameValuePair("param1", "中國"));
params.add(new BasicNameValuePair("param2"
, "value2")); //對引數編碼 String param = URLEncodedUtils.format(params, "UTF-8"); //baseUrl String baseUrl = "http://ubs.free4lab.com/php/method.php"; //將URL與引數拼接 HttpGet getMethod = new HttpGet(baseUrl + "?" + param); HttpClient httpClient = new DefaultHttpClient(); try { HttpResponse response = httpClient.execute(getMethod); //發起GET請求
Log.i(TAG, "resCode = " + response.getStatusLine().getStatusCode()); //獲取響應碼 Log.i(TAG, "result = " + EntityUtils.toString(response.getEntity(), "utf-8"));//獲取伺服器響應內容 } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block
e.printStackTrace(); }

POST方法

//和GET方式一樣,先將引數放入List
params = new LinkedList<BasicNameValuePair>();
params.add(new BasicNameValuePair("param1", "Post方法"));
params.add(new BasicNameValuePair("param2", "第二個引數"));

try {
    HttpPost postMethod = new HttpPost(baseUrl);
    postMethod.setEntity(new UrlEncodedFormEntity(params, "utf-8")); //將引數填入POST Entity中

    HttpResponse response = httpClient.execute(postMethod); //執行POST方法
    Log.i(TAG, "resCode = " + response.getStatusLine().getStatusCode()); //獲取響應碼
    Log.i(TAG, "result = " + EntityUtils.toString(response.getEntity(), "utf-8")); //獲取響應內容

} catch (UnsupportedEncodingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (ClientProtocolException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

HttpClient傳遞複雜的引數,比如檔案 需要額外的jar包

常見問題

異常處理
協議異常ClientProtocolException: 無效的cookie 很多http請求需要提供登入憑證 如果沒有則協議異常
連線超時SocketTimeoutException: 無法連線到伺服器比如伺服器不可用 那麼就連線超時
套接字超時ConnectTimeoutException: 既定時間內未收到伺服器響應此時可以連線到伺服器 但是未收到響應 那麼套接字超時

HttpConnectionparam.setconnectiontimeout(param,5000)  //連線超時時間
HttpConnectionparam.setsotimeout(param,5000) //套接字連線超時
ConnManagerParams.settimeout(param,5000)  //連線管理器的超時 定義應用程式等待多久才讓一個連線退出連線池的管理  比如連線池已經滿了 新的連線就必須要等待了

使用try catch塊來捕獲

多執行緒問題
可以設定單例的httpclient 這樣就可以共享設定的連線引數,但是單例的話 多執行緒就會有問題
HttpClient httpClient = new DefaultHttpClient(); 有多執行緒問題
比如兩個執行緒都呼叫httpClient.execute(getMethod); getMethod使用的是同一個HttpGet物件 那麼毫無疑問多執行緒問題

HttpConnectionparam.setconnectiontimeout(params,5000)
HttpConnectionparam.setsotimeout(params,5000)
ConnManagerParams.settimeout(params,5000)
HttpClient httpClient = new DefaultHttpClient(ThreadSafeClientManager conMgr,HttpParams params);

ThreadSafeClientManager負責管理所有的httpclient的http連線 內部實現不會有多執行緒問題
此時的HttpParams作用在HttpClient上,所以可以供所有的HttpGet HttpPost對像共享

如果要定義自己的連線引數 那麼可以

HttpGet getMethod = new HttpGet(baseUrl + "?" + param);
HttpParams params= getMethod.getarams();
HttpConnectionparam.setconnectiontimeout(param,5000);
getMethod.setparams(params);

此時的HttpParams作用在HttpGet上,不會影響到HttpClient共享的連線引數

AndroidHttpClient

HttpClient子類 適用於android開發人員 連線超時/套接字超時預設20s 預設是執行緒安全的ThreadSafeClientManager

HttpUrlConnection

HttpUrlConnection屬於Java的標準類庫
更輕量了 推薦使用這個 4.4開始底層通過Okhttp來實現

HttpURLConnection的多執行緒問題? 因為採取Okhttp的底層實現,是木有多執行緒的問題的,具體是為什麼,需要研究

HttpURLConnection使用

1. HttpURLConnection連線URL
1)建立一個URL物件
URL url = new URL(http://www.baidu.com);

2)利用HttpURLConnection物件從網路中獲取網頁資料
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

3)設定連線超時
conn.setConnectTimeout(6*1000);

4)對響應碼進行判斷
if (conn.getResponseCode() != 200) //從Internet獲取網頁,傳送請求,將網頁以流的形式讀回來
throw new RuntimeException(“請求url失敗”);

5)得到網路返回的輸入流
InputStream is = conn.getInputStream();
6)String result = readData(is, “GBK”); //檔案流輸入出文件用outStream.write
7)conn.disconnect();

總結:
- 記得設定連線超時,如果網路不好,Android系統在超過預設時間會收回資源中斷操作.
- 返回的響應碼200,是成功.
- 在Android中對檔案流的操作和JAVA SE上面是一樣的.
- 在對大檔案的操作時,要將檔案寫到SDCard上面,不要直接寫到手機記憶體上.
- 操作大檔案是,要一遍從網路上讀,一遍要往SDCard上面寫,減少手機記憶體的使用.
- 對檔案流操作完,要記得及時關閉.

2. 向Internet傳送請求引數
步驟:
1)建立URL物件:URL realUrl = new URL(requestUrl);
2)通過HttpURLConnection物件,向網路地址傳送請求
HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
3)設定容許輸出:conn.setDoOutput(true);
4)設定不使用快取:conn.setUseCaches(false);
5)設定使用POST的方式傳送:conn.setRequestMethod(“POST”);
6)設定維持長連線:conn.setRequestProperty(“Connection”, “Keep-Alive”);
7)設定檔案字符集:conn.setRequestProperty(“Charset”, “UTF-8”);
8)設定檔案長度:conn.setRequestProperty(“Content-Length”, String.valueOf(data.length));
9)設定檔案型別:conn.setRequestProperty(“Content-Type”,”application/x-www-form-urlencoded”);
10)以流的方式輸出.
總結:
- 傳送POST請求必須設定允許輸出
- 不要使用快取,容易出現問題.
- 在開始用HttpURLConnection物件的setRequestProperty()設定,就是生成HTML檔案頭.

3. 向Internet傳送xml資料
XML格式是通訊的標準語言,Android系統也可以通過傳送XML檔案傳輸資料.
1)將生成的XML檔案寫入到byte陣列中,並設定為UTF-8:byte[] xmlbyte = xml.toString().getBytes(“UTF-8”);
2)建立URL物件,並指定地址和引數:URL url = new URL(http://localhost:8080/itcast/contanctmanage.do?method=readxml);
3)獲得連結:HttpURLConnection conn = (HttpURLConnection) url.openConnection();
4)設定連線超時:conn.setConnectTimeout(6* 1000);
5)設定允許輸出conn.setDoOutput(true);
6)設定不使用快取:conn.setUseCaches(false);
7)設定以POST方式傳輸:conn.setRequestMethod(“POST”);
8)維持長連線:conn.setRequestProperty(“Connection”, “Keep-Alive”);
9)設定字符集:conn.setRequestProperty(“Charset”, “UTF-8”);
10)設定檔案的總長度:conn.setRequestProperty(“Content-Length”, String.valueOf(xmlbyte.length));
11)設定檔案型別:conn.setRequestProperty(“Content-Type”, “text/xml; charset=UTF-8”);
12)以檔案流的方式傳送xml資料:outStream.write(xmlbyte);
總結:
- 我們使用的是用HTML的方式傳輸檔案,這個方式只能傳輸一般在5M一下的檔案.
- 傳輸大檔案不適合用HTML的方式,傳輸大檔案我們要面向Socket程式設計.確保程式的穩定性
- 將地址和引數存到byte陣列中:byte[] data = params.toString().getBytes();

HttpClient還是HttpUrlConnection

參考 Android訪問網路,使用HttpURLConnection還是HttpClient?
在Android 2.2版本之前,HttpClient擁有較少的bug,因此使用它是最好的選擇。
而在Android 2.3版本及以後,HttpURLConnection則是最佳的選擇。它的API簡單,體積較小,因而非常適用於Android專案。壓縮和快取機制可以有效地減少網路訪問的流量,在提升速度和省電方面也起到了較大的作用。對於新的應用程式應該更加偏向於使用HttpURLConnection,因為在以後的工作當中我們也會將更多的時間放在優化HttpURLConnection上面。

其實現在嘛,兩者都不用,就用Okhttp
HttpUrlConnection現在的底層實現就是通過Okhttp

HttpURLConnection java的標準類(java.net),什麼都沒封裝,用起來太原始,不方便
HttpClient Apache開源框架,提供對HTTP協議訪問的封裝,包括http的請求頭,引數,內容體,響應等及多執行緒的應用。
HttpClient方便,但是封裝了太多,也可能導致網路請求速度變慢,靈活度不夠
HttpClient就是一個增強版的HttpURLConnection ,HttpURLConnection可以做的事情 HttpClient全部可以做;HttpURLConnection沒有提供的有些功能,HttpClient也提供了

Volley中兩者的使用

我們知道Volley中api<=9使用的是HttpClientStack,內部使用HttpClient。api>9使用的是HurlStack,內部使用HttpUrlConnection

先來看HttpClientStack,使用起來很簡單

    private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) {
        for (String key : headers.keySet()) {
            httpRequest.setHeader(key, headers.get(key));
        }
    }
    @Override
    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
            throws IOException, AuthFailureError {
        HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);
        addHeaders(httpRequest, additionalHeaders);  //快取中的頭
        addHeaders(httpRequest, request.getHeaders()); //request中的設定的頭
        onPrepareRequest(httpRequest);
        HttpParams httpParams = httpRequest.getParams();
        int timeoutMs = request.getTimeoutMs();
        // TODO: Reevaluate this connection timeout based on more wide-scale
        // data collection and possibly different for wifi vs. 3G.
        HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
        HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);
        return mClient.execute(httpRequest); //呼叫HttpClient的excute方法,執行網路請求,最後直接返回HttpResponse
    }
    static HttpUriRequest createHttpRequest(Request<?> request,
            Map<String, String> additionalHeaders) throws AuthFailureError {
            case Method.GET:
                return new HttpGet(request.getUrl());
            case Method.POST: {
                HttpPost postRequest = new HttpPost(request.getUrl());
                postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
                setEntityIfNonEmptyBody(postRequest, request); //設定post請求引數
                return postRequest;
            ........
            }
            default:
                throw new IllegalStateException("Unknown request method.");
        }
    private static void setEntityIfNonEmptyBody(HttpEntityEnclosingRequestBase httpRequest,
            Request<?> request) throws AuthFailureError {
        byte[] body = request.getBody();
        if (body != null) {
            HttpEntity entity = new ByteArrayEntity(body);
            httpRequest.setEntity(entity); //setEntity方法設定post請求引數
        }
    }

看吧,使用起來很方便簡單,都是直接封裝好了,,,下面來看HurlStack,使用起來就更負責了

   @Override
    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
            throws IOException, AuthFailureError {
        String url = request.getUrl();
        HashMap<String, String> map = new HashMap<String, String>();
        map.putAll(request.getHeaders()); //取出request設定的head
        map.putAll(additionalHeaders); //取出快取中的Header,如果該request前面發起過網路請求,那麼就會快取下來,同時會把http的head也快取
        ........
        URL parsedUrl = new URL(url);
        HttpURLConnection connection = openConnection(parsedUrl, request); //初始化HttpURLConnection物件
        for (String headerName : map.keySet()) {
            connection.addRequestProperty(headerName, map.get(headerName)); //設定Http請求的head
        }
        setConnectionParametersForRequest(connection, request);
        // Initialize HttpResponse with data from the HttpURLConnection.
        ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
        int responseCode = connection.getResponseCode();
        if (responseCode == -1) {
            // -1 is returned by getResponseCode() if the response code could not be retrieved.
            // Signal to the caller that something was wrong with the connection.
            throw new IOException("Could not retrieve response code from HttpUrlConnection.");
        }
        StatusLine responseStatus = new BasicStatusLine(protocolVersion,
                connection.getResponseCode(), connection.getResponseMessage());
        BasicHttpResponse response = new BasicHttpResponse(responseStatus); //HttpResponse需要自己建立
        if (hasResponseBody(request.getMethod(), responseStatus.getStatusCode())) {
            response.setEntity(entityFromConnection(connection)); //呼叫HttpResponse的setEntity方法設定相應內容
        }
        for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
            if (header.getKey() != null) {
                Header h = new BasicHeader(header.getKey(), header.getValue().get(0));
                response.addHeader(h); //呼叫HttpResponse的addHeader方法新增響應頭
            }
        }
        return response;
    }
    private HttpURLConnection openConnection(URL url, Request<?> request) throws IOException {
        HttpURLConnection connection = createConnection(url);

        int timeoutMs = request.getTimeoutMs();
        connection.setConnectTimeout(timeoutMs); //設定連線超時時間
        connection.setReadTimeout(timeoutMs); 
        connection.setUseCaches(false); //不使用快取?
        connection.setDoInput(true); //允許輸出

        // use caller-provided custom SslSocketFactory, if any, for HTTPS
        if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) {
            ((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory);
        }

        return connection;
    }
    //可以看到volley支援get,post,PUT等都支援的,符合http規範
    static void setConnectionParametersForRequest(HttpURLConnection connection,
            Request<?> request) throws IOException, AuthFailureError {
        switch (request.getMethod()) {
            case Method.GET:
                // Not necessary to set the request method because connection defaults to GET but
                // being explicit here.
                connection.setRequestMethod("GET");
                break;
            case Method.POST:
                connection.setRequestMethod("POST");
                addBodyIfExists(connection, request);
            ...........
        }
    }
    private static void addBodyIfExists(HttpURLConnection connection, Request<?> request)
            throws IOException, AuthFailureError {
        byte[] body = request.getBody();
        if (body != null) {
            connection.setDoOutput(true);
            connection.addRequestProperty(HEADER_CONTENT_TYPE, request.getBodyContentType()); //request的getBodyContentType()方法可以設定Content-Type請求頭
            DataOutputStream out = new DataOutputStream(connection.getOutputStream());
            out.write(body); //把getBody()返回的byte[]陣列寫入輸入流,
            out.close();
        }
    }
    private static HttpEntity entityFromConnection(HttpURLConnection connection) {
        BasicHttpEntity entity = new BasicHttpEntity();
        InputStream inputStream;
        try {
            inputStream = connection.getInputStream();
        } catch (IOException ioe) {
            inputStream = connection.getErrorStream();
        }
        entity.setContent(inputStream); //把響應內容寫入HttpEntity
        entity.setContentLength(connection.getContentLength());
        entity.setContentEncoding(connection.getContentEncoding());
        entity.setContentType(connection.getContentType());
        return entity;
    }

看到兩者的區別了吧?
HttpClient使用起來很簡單

  1. mClient.execute(httpRequest); 直接返回HttpResponse物件,這個物件封裝了響應內容和響應頭
  2. httpRequest.setHeader(key, headers.get(key)); 給請求新增頭
  3. HttpEntity entity = new ByteArrayEntity(request.getBody()); httpRequest.setEntity(entity); //給請求新增post引數

HttpURLConnection使用麻煩多了
HttpResponse物件需要自己建立,並手動新增響應內容和響應頭,這裡建立的是BasicHttpResponse實現了HttpResponse介面

  1. connection.addRequestProperty(headerName, map.get(headerName)); //設定Http請求的head
  2. DataOutputStream out = new DataOutputStream(connection.getOutputStream()); out.write(request.getBody()); //給請求新增post引數
  3. response.addHeader(h); //呼叫HttpResponse的addHeader方法新增響應頭
  4. response.setEntity(entityFromConnection(connection)); //呼叫HttpResponse的setEntity方法設定相應內容

相關推薦

Android HttpClient HttpUrlConnection用法總結

HttpClient 這個不用說了,Apache的API,但是不推薦使用了,在最新的api中甚至都把HttpClient去掉了。但是還是有必要掌握下HttpClient的用法的 GET方式 //先將引數放入List,再對引數進行URL編碼 List

Android屬性動畫用法總結

Android 3.0提供了屬性動畫,幾乎可以代替補間動畫。屬性動畫用法更加簡潔,功能更多強大。使用屬性動畫的兩個類是ValueAnimator和ObjectAnimator。 ValueAnaimator使用示例 ValueAnimator valueAn

Android之Adapter用法總結

1.概念         Adapter是連線後端資料和前端顯示的介面卡介面,是資料和UI(View)之間一個重要的紐帶。在常見的View(List View,Grid View)等地方都需要用到Adapter。如下圖直觀的表達了Data、Adapter、View三者

Android中Adapter用法總結

Adapter是Android中一個十分常見的類,在學習中經常見到,特地把網上一些相關的好資料收集了下,以便後期學習之用。 ---------------------------------------------------------------------------

Android之Adapter用法總結(糾錯)

Android之Adapter用法總結 1.概念         Adapter是連線後端資料和前端顯示的介面卡介面,是資料和UI(View)之間一個重要的紐帶。在常見的View(ListView,GridView)等地方都需要用到Adapter。如下圖直觀的表達了Dat

Android中Calendar類的用法總結

jsb ews 寫法 需要 key data- minute bar 來講 Calendar是Android開發中需要獲取時間時必不可少的一個工具類,通過這個類可以獲得的時間信息還是很豐富的,下面做一個總結,以後使用的時候就不用總是去翻書或者查資料了。 在獲取時間之前要先獲

Android框架之Glide4.x用法總結(4.8.0版本)

在Android開發軟體開發中,一定會涉及到圖片的顯示,如果需要從後臺獲取資料的話那麼Glide框架最合適不過了(本人常用),目前Glide框架已更新到4.8版本,4.8.0版本是沒有jar包的,所以可以直接新增它的依賴。 1、新增依賴 dependencies{ implement

Android Loader用法總結

Android提供了幾種非同步載入資料的方式,AsyncTaskLoader就是其中一種,這裡對它的用法做一個總結。 Android在3.0引入了Loader(載入器),支援在Activity或Fragment中非同步載入資料。想要在低版本上使用Loader可

android final關鍵字用法簡單總結

final: final修飾的變數為常量,只能賦值一次,賦值後不可修改。 final方法不能被子類重寫 final類不能被繼承 1、final變數 必須初始化,初始化必須在宣告時或者構造方法中直接賦值。不能通過函式賦值。 2、final方法 fin

Android自定義View的用法總結

1、通過減少View的使用來增加UI的顯示效率2、構建SDK中沒有的控制元件 原文總結了4種自定義View,分別是Composite View, Custom Composite View, Flat Custom View和Async Custom Views。示例程式

Android中padding的用法總結

padding left用法:padding-left:10px;  這個意思距離左邊補距10畫素,可跟百分比如(padding-left:10%;   距離左邊補10%的距離); padding right用法:padding-right:10px; 這個意思距離右邊補距

Android BitmapFactory用法總結

BitmapFactory的作用是:Creates Bitmap objects from various sources, including files, streams, and byte-arrays。常用方法如下: decodeByteArray(byte[]

git branch用法總結

如果 命名 參數 war blank org 2.6 重命名 scm Git branch git branch 不帶參數:列出本地已經存在的分支,並且在當前分支的前面加“*”號標記,例如: #git branch* master

numpy中一些常用函數的用法總結

num matrix 空白 記錄 維數 補充 結果 創建 array 先簡單記錄一下,後續補充詳細的例子 1. strip()函數 s.strip(rm):s為字符串,rm為要刪除的字符序列 只能刪除開頭或是結尾的字符或者字符串。不能刪除中間的字符或是字符串 當rm為空

數組去重,call、apply、bind之間的區別,this用法總結

步驟 -- 之間 undefined 定義 ply clas turn 需要 一、數組去重,直接寫到Array原型鏈上。 1 //該方法只能去除相同的數字 不會去判斷24和‘24‘是不同的 所有數字和字符串數字是相同是重復的 2 Array.prototype

JavaSE(一) IO類層次關系和各種IO流的用法總結

思想 單位 out 9.png 什麽 輸入流 謝謝 混亂 體系       今天把IO流的這一知點進行一下總結,因為在之前使用io流的時候,就只知道幾個重點常用的IO類,比如FileInputStream,BufferedInputStream(緩沖流)等等,但是不知道它處

最詳細的 Android Toolbar 開發實踐總結(轉)

activity resource listener nba flat xmlns mat https ons 轉自:http://www.codeceo.com/article/android-toolbar-develop.html 過年前發了一篇介紹 Transluc

netty用法總結

ram sed 解碼 coder fff ade med 長度 bte /**decoder和encoder,如果不需要解析,就使用系統的 * ch.pipeline().addLast(new StringDecoder()); * ch.pipeline().add

Android各種Adapter用法

app urn turn drawable key save 比較 logs display ArrayAdapter比較簡單,但它只能用於顯示文字。 1 public class MainActivity extends AppCompatActivity { 2

Android HttpLoggingInterceptor的用法簡介

nbsp -- ide evel clas 記錄 pla public andro 該攔截器用於記錄應用中的網絡請求的信息。 示例 OkHttpClient client = new OkHttpClient(); HttpLoggingInterceptor l