Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android應用開發入門(十一)使用Apache的HttpClient訪問Web站點

Android應用開發入門(十一)使用Apache的HttpClient訪問Web站點

編輯:Android開發實例

前言

  上一篇文章介紹了使用HttpURLConnection來完成對於HTTP協議的支持。現在介紹一個新的方式來訪問Web站點,那就是HttpClient。

  HttpClient是Apache開源組織提供的一個開源的項目,從名字上就可以看出,它是一個簡單的HTTP客戶端(並不是浏覽器),可以發送HTTP請求,接受HTTP響應。但是不會緩存服務器的響應,不能執行HTTP頁面中簽入嵌入的JS代碼,自然也不會對頁面內容進行任何解析、處理,這些都是需要開發人員來完成的。

  現在Android已經成功集成了HttpClient,所以開發人員在Android項目中可以直接使用HttpClient來想Web站點提交請求以及接受響應,如果使用其他的Java項目,需要引入進相應的Jar包。HttpClient可以在官網上下載:http://hc.apache.org/downloads.cgi

  

HttpClient

  HttpClient其實是一個interface類型,HttpClient封裝了對象需要執行的Http請求、身份驗證、連接管理和其它特性。從文檔上看,HttpClient有三個已知的實現類分別是:AbstractHttpClient, AndroidHttpClient, DefaultHttpClient,會發現有一個專門為Android應用准備的實現類AndroidHttpClient,當然使用常規的DefaultHttpClient也可以實現功能,但是既然開發的是Android應用程序,還是使用Android專有的實現類,一定有其優勢。

  從兩個類包所有在位置就可以看出區別,AndroidHttpClient定義在android.net.http.AndroidHttpClient包下,屬於Android原生的http訪問,而DefaultHttpClient定義在org.apache.http.impl.client.DefaultHttpClient包下,屬於對apche項目的支持。而AndroidHttpClient沒有公開的構造函數,只能通過靜態方法newInstance()方法來獲得AndroidHttpClient對象。

  AndroidHttpClient對於DefaultHttpClient做了一些改進,使其更使用用於Android項目:

  1. 關掉過期檢查,自連接可以打破所有的時間限制。
  2. 可以設置ConnectionTimeOut(連接超時)和SoTimeout(讀取數據超時)。
  3. 關掉重定向。
  4. 使用一個Session緩沖用於SSL Sockets。
  5. 如果服務器支持,使用gzip壓縮方式用於在服務端和客戶端傳遞的數據。
  6. 默認情況下不保留Cookie。    

  簡單來說,送HttpClient發送請求、接收響應都很簡單,只需要幾個步驟即可:

  1. 創建HttpClient對象。
  2. 創建對應的發送請求的對象,如果需要發送GET請求,則創建HttpGet對象,如果需要發送POST請求,則創建HttpPost對象。
  3. 對於發送請求的參數,GET和POST使用的方式不同,GET方式可以使用拼接字符串的方式,把參數拼接在URL結尾;POST方式需要使用setEntity(HttpEntity entity)方法來設置請求參數。
  4. 調用HttpClient對象的execute(HttpUriRequest request)發送請求,執行該方法返回一個HttpResponse對象。
  5. 調用HttpResponse的對應方法獲取服務器的響應頭、響應內容等。

DefaultHttpClient

  先看看使用DefaultHttpClient方式發送Web站點請求,上面已經簡要說明了步驟,在這裡簡要說明一個參數的傳遞問題,對於GET方式,只需要拼接字符串就在URL結尾即可,但是對於POST方式,需要傳遞HttpEntity對象,HttpEntity為一個接口,有多個實現類,可以使用其間接子繼承,UrlEncodedFormEntity類來保存請求參數,並傳遞給HttpPost。

  此例子簡單實現了在Android客戶端使用DefaultHttpClient實現一個Http站點登陸的實現,使用的是POST傳遞,其傳遞值只需要傳遞username+password即可,當傳遞的數據為admin+123則認為登陸成功。Web站點使用.net的架構,一個一般處理程序,簡單的比對賬戶密碼,這裡就不在此講解。

  因為Android4.0之後對使用網絡有特殊要求,已經無法再在主線程中訪問網絡了,必須使用多線程訪問的模式,其他的一些信息在代碼注釋中已經說明。

 DefaultHttpClient-Code

  1. package com.bgxt.httpUtils;  
  2.  
  3. import java.io.ByteArrayOutputStream;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6. import java.io.UnsupportedEncodingException;  
  7. import java.util.ArrayList;  
  8. import java.util.HashMap;  
  9. import java.util.List;  
  10. import java.util.Map;  
  11.  
  12. import org.apache.http.HttpResponse;  
  13. import org.apache.http.NameValuePair;  
  14. import org.apache.http.client.ClientProtocolException;  
  15. import org.apache.http.client.entity.UrlEncodedFormEntity;  
  16. import org.apache.http.client.methods.HttpPost;  
  17. import org.apache.http.impl.client.DefaultHttpClient;  
  18. import org.apache.http.message.BasicNameValuePair;  
  19.  
  20. public class httpClientUtils implements Runnable {  
  21.     /**  
  22.      * 對於Android4.0之上的環境下,不能在主線程中訪問網絡 所以這裡另新建了一個實現了Runnable接口的Http訪問類  
  23.      */ 
  24.     private String username;  
  25.     private String password;  
  26.  
  27.     public httpClientUtils(String username, String password) {  
  28.         // 初始化用戶名和密碼  
  29.         this.username = username;  
  30.         this.password = password;  
  31.     }  
  32.  
  33.     @Override 
  34.     public void run() {  
  35.         // 設置訪問的Web站點  
  36.         String path = "http://192.168.1.103:1231/loginas.ashx";  
  37.         // 設置Http請求參數  
  38.         Map<String, String> params = new HashMap<String, String>();  
  39.         params.put("username", username);  
  40.         params.put("password", password);  
  41.  
  42.         String result = sendHttpClientPost(path, params, "utf-8");  
  43.         // 把返回的接口輸出  
  44.         System.out.println(result);  
  45.     }  
  46.  
  47.     /**  
  48.      * 發送Http請求到Web站點  
  49.      *   
  50.      * @param path  
  51.      *            Web站點請求地址  
  52.      * @param map  
  53.      *            Http請求參數  
  54.      * @param encode  
  55.      *            編碼格式  
  56.      * @return Web站點響應的字符串  
  57.      */ 
  58.     private String sendHttpClientPost(String path, Map<String, String> map,  
  59.             String encode) {  
  60.         List<NameValuePair> list = new ArrayList<NameValuePair>();  
  61.         if (map != null && !map.isEmpty()) {  
  62.             for (Map.Entry<String, String> entry : map.entrySet()) {  
  63.                 // 解析Map傳遞的參數,使用一個鍵值對對象BasicNameValuePair保存。  
  64.                 list.add(new BasicNameValuePair(entry.getKey(), entry  
  65.                         .getValue()));  
  66.             }  
  67.         }  
  68.         try {  
  69.             // 實現將請求 的參數封裝封裝到HttpEntity中。  
  70.             UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, encode);  
  71.             // 使用HttpPost請求方式  
  72.             HttpPost httpPost = new HttpPost(path);  
  73.             // 設置請求參數到Form中。  
  74.             httpPost.setEntity(entity);  
  75.             // 實例化一個默認的Http客戶端  
  76.             DefaultHttpClient client = new DefaultHttpClient();  
  77.             // 執行請求,並獲得響應數據  
  78.             HttpResponse httpResponse = client.execute(httpPost);  
  79.             // 判斷是否請求成功,為200時表示成功,其他均問有問題。  
  80.             if (httpResponse.getStatusLine().getStatusCode() == 200) {  
  81.                 // 通過HttpEntity獲得響應流  
  82.                 InputStream inputStream = httpResponse.getEntity().getContent();  
  83.                 return changeInputStream(inputStream, encode);  
  84.             }  
  85.         } catch (UnsupportedEncodingException e) {  
  86.             e.printStackTrace();  
  87.         } catch (ClientProtocolException e) {  
  88.             e.printStackTrace();  
  89.         } catch (IOException e) {  
  90.             e.printStackTrace();  
  91.         }  
  92.         return "";  
  93.     }  
  94.  
  95.     /**  
  96.      * 把Web站點返回的響應流轉換為字符串格式  
  97.      *   
  98.      * @param inputStream  
  99.      *            響應流  
  100.      * @param encode  
  101.      *            編碼格式  
  102.      * @return 轉換後的字符串  
  103.      */ 
  104.     private String changeInputStream(InputStream inputStream, String encode) {  
  105.         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();  
  106.         byte[] data = new byte[1024];  
  107.         int len = 0;  
  108.         String result = "";  
  109.         if (inputStream != null) {  
  110.             try {  
  111.                 while ((len = inputStream.read(data)) != -1) {  
  112.                     outputStream.write(data, 0, len);  
  113.                 }  
  114.                 result = new String(outputStream.toByteArray(), encode);  
  115.  
  116.             } catch (IOException e) {  
  117.                 e.printStackTrace();  
  118.             }  
  119.         }  
  120.         return result;  
  121.     }  
  122.  

AndroidHttpClient

  使用AndroidHttpClient的方式和DefaultHttpClient差不多,不多的幾點區別上面已經說明,但是在此例子中沒有體現。有一點需要注意的是,AndroidHttpClient是一個final類,也沒有公開的構造函數,所以無法使用new的形式對其進行實例化,必須使用AndroidHttpClient.newInstance()方法獲得AndroidHttpClient對象。

  示例中依然是使用POST請求,實現的功能和DefaultHttpClient示例一樣。細節部分已經在注釋中體現,直接看代碼即可。

  1. package com.bgxt.httpUtils;  
  2.  
  3. import java.io.ByteArrayOutputStream;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6. import java.io.UnsupportedEncodingException;  
  7. import java.util.ArrayList;  
  8. import java.util.HashMap;  
  9. import java.util.List;  
  10. import java.util.Map;  
  11.  
  12. import org.apache.http.HttpResponse;  
  13. import org.apache.http.NameValuePair;  
  14. import org.apache.http.client.ClientProtocolException;  
  15. import org.apache.http.client.HttpClient;  
  16. import org.apache.http.client.entity.UrlEncodedFormEntity;  
  17. import org.apache.http.client.methods.HttpPost;  
  18. import org.apache.http.impl.client.DefaultHttpClient;  
  19. import org.apache.http.message.BasicNameValuePair;  
  20.  
  21. import android.net.http.AndroidHttpClient;  
  22.  
  23. public class AndroidHttpClientUtils implements Runnable {  
  24.  
  25.     private String username;  
  26.     private String password;  
  27.  
  28.     public AndroidHttpClientUtils(String username, String password) {  
  29.         // 初始化用戶名和密碼  
  30.         this.username = username;  
  31.         this.password = password;  
  32.     }  
  33.  
  34.     @Override 
  35.     public void run() {  
  36.         // 設置訪問的Web站點  
  37.         String path = "http://192.168.1.103:1231/loginas.ashx";  
  38.         //設置Http請求參數  
  39.         Map<String, String> params = new HashMap<String, String>();  
  40.         params.put("username", username);  
  41.         params.put("password", password);  
  42.  
  43.         String result = sendHttpClientPost(path, params, "utf-8");  
  44.         //把返回的接口輸出  
  45.         System.out.println(result);  
  46.     }  
  47.     /**  
  48.      * 發送Http請求到Web站點  
  49.      * @param path Web站點請求地址  
  50.      * @param map Http請求參數  
  51.      * @param encode 編碼格式  
  52.      * @return Web站點響應的字符串  
  53.      */ 
  54.     private String sendHttpClientPost(String path,Map<String, String> map,String encode)  
  55.     {  
  56.         List<NameValuePair> list=new ArrayList<NameValuePair>();  
  57.         if(map!=null&&!map.isEmpty())  
  58.         {  
  59.             for(Map.Entry<String, String> entry:map.entrySet())  
  60.             {  
  61.                 //解析Map傳遞的參數,使用一個鍵值對對象BasicNameValuePair保存。  
  62.                 list.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));  
  63.             }  
  64.         }  
  65.         try {  
  66.             //實現將請求 的參數封裝封裝到HttpEntity中。  
  67.             UrlEncodedFormEntity entity=new UrlEncodedFormEntity(list, encode);  
  68.             //使用HttpPost請求方式  
  69.             HttpPost httpPost=new HttpPost(path);  
  70.             //設置請求參數到Form中。  
  71.             httpPost.setEntity(entity);  
  72.             //實例化一個默認的Http客戶端,使用的是AndroidHttpClient  
  73.             HttpClient client=AndroidHttpClient.newInstance("");  
  74.             //執行請求,並獲得響應數據  
  75.             HttpResponse httpResponse= client.execute(httpPost);  
  76.             //判斷是否請求成功,為200時表示成功,其他均問有問題。  
  77.             if(httpResponse.getStatusLine().getStatusCode()==200)  
  78.             {  
  79.                 //通過HttpEntity獲得響應流  
  80.                 InputStream inputStream=httpResponse.getEntity().getContent();  
  81.                 return changeInputStream(inputStream,encode);  
  82.             }  
  83.               
  84.         } catch (UnsupportedEncodingException e) {  
  85.             // TODO Auto-generated catch block  
  86.             e.printStackTrace();  
  87.         } catch (ClientProtocolException e) {  
  88.             // TODO Auto-generated catch block  
  89.             e.printStackTrace();  
  90.         } catch (IOException e) {  
  91.             // TODO Auto-generated catch block  
  92.             e.printStackTrace();  
  93.         }  
  94.           
  95.         return "";  
  96.     }                      
  97.     /**  
  98.      * 把Web站點返回的響應流轉換為字符串格式  
  99.      * @param inputStream 響應流  
  100.      * @param encode 編碼格式  
  101.      * @return 轉換後的字符串  
  102.      */ 
  103.     private  String changeInputStream(InputStream inputStream,  
  104.             String encode) {   
  105.         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();  
  106.         byte[] data = new byte[1024];  
  107.         int len = 0;  
  108.         String result="";  
  109.         if (inputStream != null) {  
  110.             try {  
  111.                 while ((len = inputStream.read(data)) != -1) {  
  112.                     outputStream.write(data,0,len);                      
  113.                 }  
  114.                 result=new String(outputStream.toByteArray(),encode);  
  115.                   
  116.             } catch (IOException e) {  
  117.                 e.printStackTrace();  
  118.             }  
  119.         }  
  120.         return result;  
  121.     }  

 

 

  在本文的示例中,環境是使用的Android項目,可以對其進行簡單的界面布局,如圖:

  如果輸入用戶和密碼為:admin+123,則可以再LogCat中查看到登錄成功。

  示例代碼下載 

總結

  最近的兩次文章中,已經分別介紹了HttpUrlConnection和HttpClient兩種方式,通過Http協議對Web站點的訪問。如果還不了解HttpURLConnection的讀者,可以看看“ http://www.fengfly.com/plus/view-213370-1.html ”。

  根據官方文檔上說的顯示,Android包括兩個Http客戶端:HttpURLConnection和Apache HttpClient。並且都支持HTTPS,流媒體上傳下載,並且可配置超時以及支持IPv6和連接池技術。但是因為移動設備的局限性,HttpURLConnection會是比Apache Http更好的選擇,因為其API簡單,運行消耗內存小,並且具有公開化的壓縮算法,以及響應緩存,能更好的減少網絡使用,提供運行速度和節省電池。

  但是也不能否認Apache HttpClient,它有大量的靈活的API,實現比較穩定,少有Bug,可造成的問題就是很難在不影響其兼容性的情況下對其進行改進了。現在Android開發者已經慢慢放棄Apache HttpClient的使用,轉而使用HttpURLConnection。但是對於Android2.2之前的版本,HttpURLConnection具有一個致命的BUG,在響應輸入流InputStream中調用.Close()方法將會阻礙連接池,因為這個BUG,只能放棄連接池的使用,但是Apache HttpClient不存在這個問題,當然Android2.3之後的版本中,HttpURLConnection已經解決了這個BUG,可以放心使用。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved