網上介紹Android上http通訊的文章不少,不過大部分只給出了實現代碼的片斷,一些注意事項和如何設計一個合理的類用來處理全部的http請求以及返回結果,通常都不會說起。所以,本身對此作了些總結,給出了個人一個解決方案。html
首先,須要明確一下http通訊流程,Android目前提供兩種http通訊方式,HttpURLConnection和HttpClient,HttpURLConnection多用於發送或接收流式數據,所以比較適合上傳/下載文件,HttpClient相對來說更大更全能,可是速度相對也要慢一點。在此只介紹HttpClient的通訊流程:
java
1.建立HttpClient對象,改對象能夠用來屢次發送不一樣的http請求android
2.建立HttpPost或HttpGet對象,設置參數,每發送一次http請求,都須要這樣一個對象apache
3.利用HttpClient的execute方法發送請求並等待結果,該方法會一直阻塞當前線程,直到返回結果或拋出異常。json
4.針對結果和異常作相應處理服務器
根據上述流程,發如今設計類的時候,有幾點須要考慮到:網絡
1.HttpClient對象能夠重複使用,所以能夠做爲類的靜態變量app
2.HttpPost/HttpGet對象通常沒法重複使用(若是你每次請求的參數都差很少,也能夠重複使用),所以能夠建立一個方法用來初始化,同時設置一些須要上傳到服務器的資源socket
3.目前Android再也不支持在UI線程中發起Http請求,實際上也不應這麼作,由於這樣會阻塞UI線程。所以還須要一個子線程,用來發起Http請求,即執行execute方法ide
4.不一樣的請求對應不一樣的返回結果,對於如何處理返回結果(通常來講都是解析json&更新UI),須要有必定的自由度。
5.最簡單的方法是,每次須要發送http請求時,開一個子線程用於發送請求,子線程中接收到結果或拋出異常時,根據狀況給UI線程發送message,最後在UI線程的handler的handleMessage方法中作結果解析和UI更新。這麼寫雖然簡單,可是UI線程和Http請求的耦合度很高,並且代碼比較散亂、醜陋。
基於上述幾點緣由,我設計了一個PostRequest類,用於知足個人http通訊需求。我只用到了Post請求,若是你須要Get請求,也能夠改寫成GetRequest
package com.handspeaker.network; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.http.protocol.HTTP; import org.apache.http.util.EntityUtils; import org.json.JSONObject; import android.app.Activity; import android.content.Context; import android.net.ConnectivityManager; import android.os.Handler; import android.util.Log; /** * * 用於封裝&簡化http通訊 * */ public class PostRequest implements Runnable { private static final int NO_SERVER_ERROR=1000; //服務器地址 public static final String URL = "fill your own url"; //一些請求類型 public final static String ADD = "/add"; public final static String UPDATE = "/update"; public final static String PING = "/ping"; //一些參數 private static int connectionTimeout = 60000; private static int socketTimeout = 60000; //類靜態變量 private static HttpClient httpClient=new DefaultHttpClient(); private static ExecutorService executorService=Executors.newCachedThreadPool(); private static Handler handler = new Handler(); //變量 private String strResult; private HttpPost httpPost; private HttpResponse httpResponse; private OnReceiveDataListener onReceiveDataListener; private int statusCode; /** * 構造函數,初始化一些能夠重複使用的變量 */ public PostRequest() { strResult = null; httpResponse = null; httpPost = new HttpPost(); } /** * 註冊接收數據監聽器 * @param listener */ public void setOnReceiveDataListener(OnReceiveDataListener listener) { onReceiveDataListener = listener; } /** * 根據不一樣的請求類型來初始化httppost * * @param requestType * 請求類型 * @param nameValuePairs * 須要傳遞的參數 */ public void iniRequest(String requestType, JSONObject jsonObject) { httpPost.addHeader("Content-Type", "text/json"); httpPost.addHeader("charset", "UTF-8"); httpPost.addHeader("Cache-Control", "no-cache"); HttpParams httpParameters = httpPost.getParams(); HttpConnectionParams.setConnectionTimeout(httpParameters, connectionTimeout); HttpConnectionParams.setSoTimeout(httpParameters, socketTimeout); httpPost.setParams(httpParameters); try { httpPost.setURI(new URI(URL + requestType)); httpPost.setEntity(new StringEntity(jsonObject.toString(), HTTP.UTF_8)); } catch (URISyntaxException e1) { e1.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } /** * 新開一個線程發送http請求 */ public void execute() { executorService.execute(this); } /** * 檢測網絡情況 * * @return true is available else false */ public static boolean checkNetState(Activity activity) { ConnectivityManager connManager = (ConnectivityManager) activity .getSystemService(Context.CONNECTIVITY_SERVICE); if (connManager.getActiveNetworkInfo() != null) { return connManager.getActiveNetworkInfo().isAvailable(); } return false; } /** * 發送http請求的具體執行代碼 */ @Override public void run() { httpResponse = null; try { httpResponse = httpClient.execute(httpPost); strResult = EntityUtils.toString(httpResponse.getEntity()); } catch (ClientProtocolException e1) { strResult = null; e1.printStackTrace(); } catch (IOException e1) { strResult = null; e1.printStackTrace(); } finally { if (httpResponse != null) { statusCode = httpResponse.getStatusLine().getStatusCode(); } else { statusCode=NO_SERVER_ERROR; } if(onReceiveDataListener!=null) { //將註冊的監聽器的onReceiveData方法加入到消息隊列中去執行 handler.post(new Runnable() { @Override public void run() { onReceiveDataListener.onReceiveData(strResult, statusCode); } }); } } } /** * 用於接收並處理http請求結果的監聽器 * */ public interface OnReceiveDataListener { /** * the callback function for receiving the result data * from post request, and further processing will be done here * @param strResult the result in string style. * @param StatusCode the status of the post */ public abstract void onReceiveData(String strResult,int StatusCode); } }
代碼使用了觀察者模式,任何須要接收http請求結果的類,都要實現OnReceiveDataListener接口的抽象方法,同時PostRequest實例調用setOnReceiveDataListener方法,註冊該監聽器。完整調用步驟以下:
1.建立PostRequest對象,實現onReceiveData接口,編寫本身的onReceiveData方法
2.註冊監聽器
3.調用PostRequest的iniRequest方法,初始化本次request
4.調用PostRequest的execute方法
可能的改進:
1.若是須要多個觀察者,能夠把只能註冊單個監聽器改成能夠註冊多個監聽器,維護一個監聽器List。
2.若是需求比較簡單,並但願調用流程更簡潔,iniRequest和execute能夠合併