編輯: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項目:
簡單來說,送HttpClient發送請求、接收響應都很簡單,只需要幾個步驟即可:
DefaultHttpClient
先看看使用DefaultHttpClient方式發送Web站點請求,上面已經簡要說明了步驟,在這裡簡要說明一個參數的傳遞問題,對於GET方式,只需要拼接字符串就在URL結尾即可,但是對於POST方式,需要傳遞HttpEntity對象,HttpEntity為一個接口,有多個實現類,可以使用其間接子繼承,UrlEncodedFormEntity類來保存請求參數,並傳遞給HttpPost。
此例子簡單實現了在Android客戶端使用DefaultHttpClient實現一個Http站點登陸的實現,使用的是POST傳遞,其傳遞值只需要傳遞username+password即可,當傳遞的數據為admin+123則認為登陸成功。Web站點使用.net的架構,一個一般處理程序,簡單的比對賬戶密碼,這裡就不在此講解。
因為Android4.0之後對使用網絡有特殊要求,已經無法再在主線程中訪問網絡了,必須使用多線程訪問的模式,其他的一些信息在代碼注釋中已經說明。
DefaultHttpClient-Code
- package com.bgxt.httpUtils;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.UnsupportedEncodingException;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import org.apache.http.HttpResponse;
- import org.apache.http.NameValuePair;
- import org.apache.http.client.ClientProtocolException;
- import org.apache.http.client.entity.UrlEncodedFormEntity;
- import org.apache.http.client.methods.HttpPost;
- import org.apache.http.impl.client.DefaultHttpClient;
- import org.apache.http.message.BasicNameValuePair;
- public class httpClientUtils implements Runnable {
- /**
- * 對於Android4.0之上的環境下,不能在主線程中訪問網絡 所以這裡另新建了一個實現了Runnable接口的Http訪問類
- */
- private String username;
- private String password;
- public httpClientUtils(String username, String password) {
- // 初始化用戶名和密碼
- this.username = username;
- this.password = password;
- }
- @Override
- public void run() {
- // 設置訪問的Web站點
- String path = "http://192.168.1.103:1231/loginas.ashx";
- // 設置Http請求參數
- Map<String, String> params = new HashMap<String, String>();
- params.put("username", username);
- params.put("password", password);
- String result = sendHttpClientPost(path, params, "utf-8");
- // 把返回的接口輸出
- System.out.println(result);
- }
- /**
- * 發送Http請求到Web站點
- *
- * @param path
- * Web站點請求地址
- * @param map
- * Http請求參數
- * @param encode
- * 編碼格式
- * @return Web站點響應的字符串
- */
- private String sendHttpClientPost(String path, Map<String, String> map,
- String encode) {
- List<NameValuePair> list = new ArrayList<NameValuePair>();
- if (map != null && !map.isEmpty()) {
- for (Map.Entry<String, String> entry : map.entrySet()) {
- // 解析Map傳遞的參數,使用一個鍵值對對象BasicNameValuePair保存。
- list.add(new BasicNameValuePair(entry.getKey(), entry
- .getValue()));
- }
- }
- try {
- // 實現將請求 的參數封裝封裝到HttpEntity中。
- UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, encode);
- // 使用HttpPost請求方式
- HttpPost httpPost = new HttpPost(path);
- // 設置請求參數到Form中。
- httpPost.setEntity(entity);
- // 實例化一個默認的Http客戶端
- DefaultHttpClient client = new DefaultHttpClient();
- // 執行請求,並獲得響應數據
- HttpResponse httpResponse = client.execute(httpPost);
- // 判斷是否請求成功,為200時表示成功,其他均問有問題。
- if (httpResponse.getStatusLine().getStatusCode() == 200) {
- // 通過HttpEntity獲得響應流
- InputStream inputStream = httpResponse.getEntity().getContent();
- return changeInputStream(inputStream, encode);
- }
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- } catch (ClientProtocolException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return "";
- }
- /**
- * 把Web站點返回的響應流轉換為字符串格式
- *
- * @param inputStream
- * 響應流
- * @param encode
- * 編碼格式
- * @return 轉換後的字符串
- */
- private String changeInputStream(InputStream inputStream, String encode) {
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- byte[] data = new byte[1024];
- int len = 0;
- String result = "";
- if (inputStream != null) {
- try {
- while ((len = inputStream.read(data)) != -1) {
- outputStream.write(data, 0, len);
- }
- result = new String(outputStream.toByteArray(), encode);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- return result;
- }
- }
AndroidHttpClient
使用AndroidHttpClient的方式和DefaultHttpClient差不多,不多的幾點區別上面已經說明,但是在此例子中沒有體現。有一點需要注意的是,AndroidHttpClient是一個final類,也沒有公開的構造函數,所以無法使用new的形式對其進行實例化,必須使用AndroidHttpClient.newInstance()方法獲得AndroidHttpClient對象。
示例中依然是使用POST請求,實現的功能和DefaultHttpClient示例一樣。細節部分已經在注釋中體現,直接看代碼即可。
- package com.bgxt.httpUtils;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.UnsupportedEncodingException;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import org.apache.http.HttpResponse;
- import org.apache.http.NameValuePair;
- import org.apache.http.client.ClientProtocolException;
- import org.apache.http.client.HttpClient;
- import org.apache.http.client.entity.UrlEncodedFormEntity;
- import org.apache.http.client.methods.HttpPost;
- import org.apache.http.impl.client.DefaultHttpClient;
- import org.apache.http.message.BasicNameValuePair;
- import android.net.http.AndroidHttpClient;
- public class AndroidHttpClientUtils implements Runnable {
- private String username;
- private String password;
- public AndroidHttpClientUtils(String username, String password) {
- // 初始化用戶名和密碼
- this.username = username;
- this.password = password;
- }
- @Override
- public void run() {
- // 設置訪問的Web站點
- String path = "http://192.168.1.103:1231/loginas.ashx";
- //設置Http請求參數
- Map<String, String> params = new HashMap<String, String>();
- params.put("username", username);
- params.put("password", password);
- String result = sendHttpClientPost(path, params, "utf-8");
- //把返回的接口輸出
- System.out.println(result);
- }
- /**
- * 發送Http請求到Web站點
- * @param path Web站點請求地址
- * @param map Http請求參數
- * @param encode 編碼格式
- * @return Web站點響應的字符串
- */
- private String sendHttpClientPost(String path,Map<String, String> map,String encode)
- {
- List<NameValuePair> list=new ArrayList<NameValuePair>();
- if(map!=null&&!map.isEmpty())
- {
- for(Map.Entry<String, String> entry:map.entrySet())
- {
- //解析Map傳遞的參數,使用一個鍵值對對象BasicNameValuePair保存。
- list.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
- }
- }
- try {
- //實現將請求 的參數封裝封裝到HttpEntity中。
- UrlEncodedFormEntity entity=new UrlEncodedFormEntity(list, encode);
- //使用HttpPost請求方式
- HttpPost httpPost=new HttpPost(path);
- //設置請求參數到Form中。
- httpPost.setEntity(entity);
- //實例化一個默認的Http客戶端,使用的是AndroidHttpClient
- HttpClient client=AndroidHttpClient.newInstance("");
- //執行請求,並獲得響應數據
- HttpResponse httpResponse= client.execute(httpPost);
- //判斷是否請求成功,為200時表示成功,其他均問有問題。
- if(httpResponse.getStatusLine().getStatusCode()==200)
- {
- //通過HttpEntity獲得響應流
- InputStream inputStream=httpResponse.getEntity().getContent();
- return changeInputStream(inputStream,encode);
- }
- } 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();
- }
- return "";
- }
- /**
- * 把Web站點返回的響應流轉換為字符串格式
- * @param inputStream 響應流
- * @param encode 編碼格式
- * @return 轉換後的字符串
- */
- private String changeInputStream(InputStream inputStream,
- String encode) {
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- byte[] data = new byte[1024];
- int len = 0;
- String result="";
- if (inputStream != null) {
- try {
- while ((len = inputStream.read(data)) != -1) {
- outputStream.write(data,0,len);
- }
- result=new String(outputStream.toByteArray(),encode);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- return result;
- }
- }
在本文的示例中,環境是使用的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,可以放心使用。
SlidingDrawer隱藏屏外的內容,並允許用戶通過handle以顯示隱藏內容。它可以垂直或水平滑動,它有倆個View組成,其一是可以拖動的handle,其二
可以顯示在的Android任務,通過加載進度條的進展。進度條有兩種形狀。加載欄和加載微調(spinner)。在本章中,我們將討論微調(spinner)。Spinner 用
Android應用程序可以在許多不同地區的許多設備上運行。為了使應用程序更具交互性,應用程序應該處理以適合應用程序將要使用的語言環境方面的文字,數字,文件等。在本章中,我
本文實例講述了Android編程之界面跳動提示動畫效果實現方法。分享給大家供大家參考,具體如下: 上一個效果圖: 先上布局: <RelativeLa