編輯:關於Android編程
在 Android 開發中我們經常用到網絡鏈接功能 與 服務器進行數據交互,為此android SDK 提供 Apache 的 HttpClient 來方便 我們使用各種Http 服務,
我們可以寫一段 示例代碼:
HttpClient httpClient = new DefaultHttpClient();
// 創建一個Get 請求
HttpGet request = new HttpGet("uri");
// 發送GET請求,並將響應內容轉換成字符串
String response = httpclient.execute(request, new BasicResponseHandler());
Log.v("response text", response);
為什麼要使用單例HttpClient?
這只是一段演示代碼,實際的項目中的請求與響應處理會復雜一些,並且還要考慮到代碼的容錯性,但是這並不是本篇的重點
HttpClient httpclient = new DefaultHttpClient();
在發出HTTP請求前,我們先創建了一個HttpClient對象。那麼,在實際項目中,我們很可能在多處需要進行HTTP通信,這時候我們不需要為每個請求都創建一個新的HttpClient。因為之前已經提到,HttpClient就像一個小型的浏覽器,對於整個應用,我們只需要一個HttpClient就夠了。看到這裡,一定有人心裡想,這有什麼難的,用單例啊!!就像這樣:
public class CustomerHttpClient {
private static HttpClient customerHttpClient;
private CustomerHttpClient() {
}
public static HttpClient getHttpClient() {
if(null == customerHttpClient) {
customerHttpClient = new DefaultHttpClient();
}
return customerHttpClient;
}
}
但是對於多個請求的怎麼處理呢? 請求A 請求B 怎麼同時處理呢?
在采用上述的處理方式,如何?
所以我們采用多線程來處理,解決多線程問題 還好HttpClient 給處理了
public class CustomerHttpClient {
private static final String CHARSET = HTTP.UTF_8;
private static HttpClient customerHttpClient;
private CustomerHttpClient() {
}
public static synchronized HttpClient getHttpClient() {
if (null == customerHttpClient) {
HttpParams params = new BasicHttpParams();
// 設置一些基本參數
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params,
CHARSET);
HttpProtocolParams.setUseExpectContinue(params, true);
HttpProtocolParams
.setUserAgent(
params,
"Mozilla/5.0(Linux;U;Android 2.2.1;en-us;Nexus One Build.FRG83) "
+ "AppleWebKit/553.1(KHTML,like Gecko) Version/4.0 Mobile Safari/533.1");
// 超時設置
/* 從連接池中取連接的超時時間 */
ConnManagerParams.setTimeout(params, 1000);
/* 連接超時 */
HttpConnectionParams.setConnectionTimeout(params, 2000);
/* 請求超時 */
HttpConnectionParams.setSoTimeout(params, 4000);
// 設置我們的HttpClient支持HTTP和HTTPS兩種模式
SchemeRegistry schReg = new SchemeRegistry();
schReg.register(new Scheme("http", PlainSocketFactory
.getSocketFactory(), 80));
schReg.register(new Scheme("https", SSLSocketFactory
.getSocketFactory(), 443));
// 使用線程安全的連接管理來創建HttpClient
ClientConnectionManager conMgr = new ThreadSafeClientConnManager(
params, schReg);
customerHttpClient = new DefaultHttpClient(conMgr, params);
}
return customerHttpClient;
}
}
在上面的getHttpClient () 方法中,我們為HttpClient 配置了一些基本參數和超時設置,然後使用,ThreadSafeClientConnManager 來創建線程安全的HttpClient
HttpClient 的三種超時說明
/* 從連接池中取連接的超時時間 */
ConnManagerParams.setTimeout(params, 1000);
/* 連接超時 */
HttpConnectionParams.setConnectionTimeout(params, 2000);
/* 請求超時 */
HttpConnectionParams.setSoTimeout(params, 4000);
第一行設置ConnectionPoolTimeout:這定義了從ConnectionManager管理的連接池中取出連接的超時時間,此處設置為1秒。
第二行設置ConnectionTimeout:這定義了通過網絡與服務器建立連接的超時時間。Httpclient包中通過一個異步線程去創建與服務器的socket連接,這就是該socket連接的超時時間,此處設置為2秒。
第三行設置SocketTimeout:這定義了Socket讀數據的超時時間,即從服務器獲取響應數據需要等待的時間,此處設置為4秒。
以上3種超時分別會拋出ConnectionPoolTimeoutException,ConnectionTimeoutException與SocketTimeoutException。
封裝簡單的POST請求
有了單例的HttpClient對象,我們就可以把一些常用的發出GET和POST請求的代碼也封裝起來,寫進我們的工具類中了。目前我僅僅實現發出POST請求並返回響應字符串的方法以供大家參考。將以下代碼加入我們的CustomerHttpClient類中:
private static final String TAG = "CustomerHttpClient";
public static String post(String url, NameValuePair... params) {
try {
// 編碼參數
List<NameValuePair> formparams = new ArrayList<NameValuePair>(); // 請求參數
for (NameValuePair p : params) {
formparams.add(p);
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams,
CHARSET);
// 創建POST請求
HttpPost request = new HttpPost(url);
request.setEntity(entity);
// 發送請求
HttpClient client = getHttpClient();
HttpResponse response = client.execute(request);
if(response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new RuntimeException("請求失敗");
}
HttpEntity resEntity = response.getEntity();
return (resEntity == null) ? null : EntityUtils.toString(resEntity, CHARSET);
} catch (UnsupportedEncodingException e) {
Log.w(TAG, e.getMessage());
return null;
} catch (ClientProtocolException e) {
Log.w(TAG, e.getMessage());
return null;
} catch (IOException e) {
throw new RuntimeException("連接失敗", e);
}
}
使用我們的CustomerHttpClient工具類
現在,在整個項目中我們都能很方便的使用該工具類來進行網絡通信的業務代碼編寫了。下面的代碼演示了如何使用username和password注冊一個賬戶並得到新賬戶ID。
final String url = "http://yourdomain/context/adduser";
//准備數據
NameValuePair param1 = new BasicNameValuePair("username", "張三");
NameValuePair param2 = new BasicNameValuePair("password", "123456");
int resultId = -1;
try {
// 使用工具類直接發出POST請求,服務器返回json數據,比如"{userid:12}"
String response = CustomerHttpClient.post(url, param1, param2);
JSONObject root = new JSONObject(response);
resultId = Integer.parseInt(root.getString("userid"));
Log.i(TAG, "新用戶ID:" + resultId);
} catch (RuntimeException e) {
// 請求失敗或者連接失敗
Log.w(TAG, e.getMessage());
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT);
} catch (Exception e) {
// JSon解析出錯
Log.w(TAG, e.getMessage());
}
點擊按鈕刷新1、效果如下:實例如下: 上圖的添加數據按鈕可以換成一個進度條 因為沒有數據所以我加了一個按鈕添加到數據庫用於測試;一般在服務器拉去數
ListView是我們在開發Android程序時用得比較多的一種widget,通常用來展示多條數據,這裡,我對ListView的一些功能點作一個簡單介紹。 1. Ca
ImageView有scaleType屬性可以縮放圖片,讓圖片鋪滿屏幕寬度,但是會出現壓縮或裁剪的情況。ImageView的scaleType的屬性分別是ma
最近想弄一個雙導航功能,查看了許多資料,總算是實現了功能,這邊就算是給自己幾個筆記吧! 先來看看效果 那麼就開始實現了! 底部導航欄我選擇用