close
Android使用HttpClient與HttpURLConnection連線範例
在看過上一篇JSON的應用後,可以來使用HTTP連線
在Android開發中,Android SDK附帶了Apache的HttpClient,他是一個完善的客戶端,提供了對HTTP協定全面的支援
可以使用HttpClient的對象來執行HTTP GET、HTTP POST得調用
HTTP工作原理:
1.客戶端(一般是指瀏覽器,這裡是指自己寫的程式)與伺服器建立連接
2.建立連接後客戶端向伺服器發送訊息
3.伺服器接收到訊息後,向客戶端發送回應訊息
4.客戶端與伺服器斷開連接
HttpClient的一般使用步驟:
1.使用DefaultHttpClient類型實做HttpClient物件
2.創建HttpGet或HttpPost物件,將請求的URL通過建構的方法傳入HttpGet或HttpPost物件
3.調用execute方法發送HTTP GET或HTTP POST請求,並回傳給HttpResponse物件
4.通過HttpResponse接口的getEntity方法取得伺服器回應的訊息,並進行相應的處理
最後記得在AndroidManifest.xml文件添加網路權限
<uses-permission android:name="android.permission.INTERNET" />
GET、POST方式的差別:
1.GET是從伺服器上取得數據,POST是向伺服器傳送數據
2.在客戶端,GET方式在通過URL提交數據,數據在URL中可以看到,POST方式數據放在HTML HEADER內提交
3.對於GET方式,伺服器端用Request.QueryString獲取變數的值,對於POST方式,伺服器用Request.Form獲取提交的數據
4.GET方式提交的數據大於2KB(主要是URL長度限制),而POST則沒有此限制
5.安全性問題,正如差別2.提到,使用GET的時候,參數會顯示在地址欄上,而POST不會,所以如果這些是中文數據而且是非敏感數據,那麼使用GET
如果用戶輸入的數據不是中文字元而且包含敏感數據,那麼還是使用POST數據為好
HttpClient其實是一個interface(介面、接口)類型,HttpClient封裝了物件需要執行的Http請求、身份驗證、連接管理和其他特性
HttpClient有三個已知的實作類別:AbstractHttpClient, AndroidHttpClient, DefaultHttpClient
AndroidHttpClient為專門為Android應用準備的,雖然常規的DefaultHttpClient也可以實現功能,但Android專用的有一定的優勢
因沒有實際使用過AndroidHttpClient,以下只示範DefaultHttpClient:
在使用GET方式只需要拼接字串在URL結尾即可,但POST方式需要傳遞HttpEntity物件,
HttpEntity為一個接口可以使用他的間接子繼承,UrlEncodedFormEntity類型來保存請求參數,並傳遞給HttpPost
此範例簡單實現Android客戶端使用DefaultHttpClient,使用的是POST傳遞,
(因GET方式有安全性問題,且長度上有限制,所以以下只使用POST傳遞方式)
將要傳輸的資料丟進Map<String, String>,再給予網路php路徑,實作該物件後調用sendHttpClientPost()即可回傳String result
//需先判斷result是否為"",沒內容則代表連線請求失敗(或本身就沒回傳內容) result=result.substring(result.indexOf("{"), result.lastIndexOf("}") + 1); //將取到的String抓取{}範圍資料 JSONObject json=new JSONObject(result); //裝進JSONObject後依序取值
import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; 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.util.Log; @SuppressWarnings("deprecation") public class HttpClient_POST { private String path; //儲存網路php路徑 private Map<String, String> map; //儲存要送的值 private String encode="utf-8"; //儲存編碼 //建構子(網路php路徑,要送的值) public HttpClient_POST(String path,Map<String, String> map){ this.path=path; this.map=map; } //發送HttpClient_Post(網址,資料內容,編碼方式) public String sendHttpClientPost() { List<NameValuePair> list = new ArrayList<NameValuePair>(); //宣告型態成對的鏈結串列list if (map != null && !map.isEmpty()) { //判斷map是否非null或有初始化 //entrySet()會得到map內的key-value成對的集合,並回傳 for (Map.Entry<String, String> entry : map.entrySet()) { list.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); //將設置好的請求參數寫進list //基本型態成對都可使用 new BasicNameValuePair() //Map.Entry內提供了getKey()、getValue()、setValue(),雖然增加一行卻省略了很多對Map不必要的get調用 } Log.i("text","Http_Client.list傳送資料="+list.toString()); } try { //將請求的參數與編碼方式,封裝到HttpEntity內的子繼承UrlEncodedFormEntity中 UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, encode); //建造HttpPost物件並給予path(網址) HttpPost httpPost = new HttpPost(path); //設置請求參數 httpPost.setEntity(entity); // 實做一個默認的Http客戶端 DefaultHttpClient client = new DefaultHttpClient(); //執行請求,並接收回傳資料 HttpResponse httpResponse = client.execute(httpPost); //判斷是否請求成功,為200時表示成功,其他均有問題 if (httpResponse.getStatusLine().getStatusCode() == 200) { //透過HttpEntity獲得物件內容並設給inputStream (輸入流串) InputStream inputStream = httpResponse.getEntity().getContent(); //回傳輸入串流的encode編碼方式內容 return changeInputStream(inputStream); } } catch (Exception e) { e.printStackTrace(); Log.e("text","Http_Client="+e.toString()); } return ""; } public String changeInputStream(InputStream inputStream) { //將輸入串流轉成字串回傳 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); //ByteArrayOutputStream型態可不斷寫入來增長緩存區,可使用toByteArray()、toString()獲取數據 byte[] data = new byte[1024]; int len = 0; String result = ""; if (inputStream != null) { //判斷inputStream是否非空字串 try { while ((len = inputStream.read(data)) != -1) { //將inputStream寫入data並回傳字數到len outputStream.write(data, 0, len); //將data寫入到輸出流中,參數二為起始位置,len是讀取長度 } result = new String(outputStream.toByteArray(), encode); //resilt取得outputStream的string並轉成encode邊碼 } catch (IOException e) { e.printStackTrace(); Log.e("text", "Http_Client.changeInputStream.IOException="+e.toString()); } } return result; //回傳result } }
apache HTTPclient高效穩定,但是維護成本高昂,故android 開發團隊不願意在維護該庫而是轉投更為輕便的HttpURLConnection
HttpURLConnection比較輕便,靈活和易於擴展,它在2.2前存在這樣一個BUG,
所以在2.2版本前使用HttpClient,而在之後的版本使用HttpURLConnection,以下為HttpURLConnection使用的一樣是POST傳遞,
將要傳輸的資料丟進Map<String, String>,再給予網路php路徑,實作該物件後調用sendHttpURLConnectionPOST()即可回傳String result
//需先判斷result是否為"",沒內容則代表連線請求失敗(或本身就沒回傳內容) result=result.substring(result.indexOf("{"), result.lastIndexOf("}") + 1); //將取到的String抓取{}範圍資料 JSONObject json=new JSONObject(result); //裝進JSONObject後依序取值
import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; import java.util.Map; import android.util.Log; public class HttpURLConnection_POST { private URL url; //儲存網路php路徑 private Map<String, String> map; //儲存要送的值 private String encode="utf-8"; //儲存編碼 //建構子(網路php路徑,要送的值) public HttpURLConnection_POST(String path,Map<String, String> map){ try { this.url=new URL(path); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } this.map=map; } //發送HttpURLConnection_POST(網址,資料內容,編碼方式) public String sendHttpURLConnectionPOST() { try { //打開服務器 HttpURLConnection hucn=(HttpURLConnection) url.openConnection(); hucn.setReadTimeout(5000); //設置讀取超時為5秒 hucn.setConnectTimeout(10000); //設置連接網路超時為10秒 //設置輸出入流串 hucn.setDoOutput(true); //可寫入資料至伺服器 hucn.setDoInput(true); //可從伺服器取得資料 //設置請求的方法為POST hucn.setRequestMethod("POST"); //POST方法不能緩存數據,需手動設置使用緩存的值為false hucn.setUseCaches(false); //連接資料庫 //hucn.connect(); //如使用調用getResponseCode()判斷是否為200 就不必使用connect() //寫入參數 OutputStream os=hucn.getOutputStream(); //設置輸出流串 DataOutputStream dos=new DataOutputStream(os); //封裝寫給伺服器的資料,需存進這裡 if (map != null && !map.isEmpty()) { //判斷map是否非null或有初始化 String str=null; //用來存傳送參數 //entrySet()會得到map內的key-value成對的集合,並回傳 for (Map.Entry<String, String> entry : map.entrySet()) { if(str==null) //判斷是否為第一次調用 str=entry.getKey()+"="+URLEncoder.encode(entry.getValue(),encode); else str=str+"&"+entry.getKey()+"="+URLEncoder.encode(entry.getValue(),encode); //Key值不變,Value轉成UTF-8編碼可使用中文 //Map.Entry內提供了getKey()、getValue()、setValue(),雖然增加一行卻省略了很多對Map不必要的get調用 } dos.writeBytes(str); //將設置好的請求參數寫進dos //顯示時必須進行解碼,否則看到的中文會變成亂碼 Log.i("text","HttpURLConnection_POST.dos傳送資料="+java.net.URLDecoder.decode(str,encode)); } //輸出完關閉輸出流 dos.flush(); dos.close(); //判斷是否請求成功,為200時表示成功,其他均有問題 if(hucn.getResponseCode() == 200){ //取得回傳的inputStream (輸入流串) InputStream inputStream = hucn.getInputStream(); return changeInputStream(inputStream); } } catch (Exception e) { e.printStackTrace(); Log.e("text","HttpURLConnection_POST="+e.toString()); } return ""; } public String changeInputStream(InputStream inputStream) { //將輸入串流轉成字串回傳 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); //ByteArrayOutputStream型態可不斷寫入來增長緩存區,可使用toByteArray()、toString()獲取數據 byte[] data = new byte[1024]; int len = 0; String result = ""; if (inputStream != null) { //判斷inputStream是否非空字串 try { while ((len = inputStream.read(data)) != -1) { //將inputStream寫入data並回傳字數到len outputStream.write(data, 0, len); //將data寫入到輸出流中,參數二為起始位置,len是讀取長度 } result = new String(outputStream.toByteArray(), encode); //resilt取得outputStream的string並轉成encode邊碼 } catch (IOException e) { e.printStackTrace(); Log.e("text", "Http_Client.changeInputStream.IOException="+e.toString()); } } return result; //回傳result } }
==================================================
必須注意Android 4.0 之後,有明文規定所有的網路行為都不能在主執行緒(Main Thread)執行,主執行緒又稱UI執行緒(UI Thread),如果要在主執行緒做網路的事,就需要使用Thread-執行緒或是AsyncTask-異步任務
以上為兩種HTTP連線所寫的物件與用法,必須在伺服器上在寫對應的php檔
目前只有在寫小作品時使用過連伺服器上的php檔,如有學到進一步的用法會再上來修改
文章標籤
全站熱搜
留言列表