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檔,如有學到進一步的用法會再上來修改




arrow
arrow
    創作者介紹
    創作者 SIN 的頭像
    SIN

    SIN-Android學習筆記

    SIN 發表在 痞客邦 留言(5) 人氣()