標籤:
目錄(?)[-]
- 應用共用HttpClient對象的同步問題
- 建立共用HttpClient代碼
- 建立共用對象
- 建立可共用的HttpClient對象
- 使用共用HttpClient對象的代碼
- 基礎代碼
- 修改HTTP串連的參數
- 使用共同的Appcliation對象
文章轉載只能用於非商業性質,且不能帶有虛擬貨幣、積分、註冊等附加條件,轉載須註明出處:http://blog.csdn.net/flowingflying/
應用共用HttpClient對象的同步問題
在之前的例子中,HttpClient只用於某個請求,我們可以為整個應用建立一個共用的HttpClient對象。這就存在多線程使用的問題,而HttpClient已經考慮這個問題,只需要建立一個使用ThreadSafeClientConnManager的DefaultHttpClient對象。
建立共用HttpClient代碼建立共用對象
建立共用對象的方式是通用,如下:
public class CustomHttpClient {
private static HttpClient client = null; //應用共用的對象
/* 採用private的構造器,禁止了其他類通過CustomHttpClient xx = new CustomHttpClient();這種方式建立對象,確保對象的唯一性 */
private CustomHttpClient(){
}
/* 通過靜態調用擷取對象,第一次調用為空白時進行建立 */
public static synchronized HttpClient getCustomHttpClient(){
if(client == null){
/*如果對象為空白,建立之*/
... ...
}
return client;
}
/*禁止clone,同樣也是保證對象的唯一性*/
public Object clone() throws CloneNotSupportedException{
throw new CloneNotSupportedException();
}
}
建立可共用的HttpClient對象
下面給出上面代碼中省略的部分,當對象為空白是,建立HttpClient對象的代碼,為了方便理解,代碼從可以從後往前看。
//【2.1】設定Http參數
HttpParams params = new BasicHttpParams();
/* 設定HttpParam是的基本參數,其實都是對應http請求的訊息頭。其中三個都很好理解,重點介紹一些setUserExpectContinue。 一般都設定為flase,設定為true通常是傳遞request訊息很大(例攜帶大檔案),而伺服器可能需要認證,我們不希望傳完這個大檔案,才收到伺服器的拒絕。HTTP是TCP流方式,當server收到請求的頭欄位是Except:100-continue, 不在等待整個請求,返回100 continue應答繼續讀取,或者給出拒絕請求(final Status code,如4xx)。 具體可以參考:http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3 */
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
HttpProtocolParams.setUseExpectContinue(params, true);
HttpProtocolParams.setUserAgent(params, "Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; Nexus One Build/FRG83)" +
" AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1");
/* 設定逾時時間。逾時的異常均屬於IOException,此外ClientProtocolException也是與IOException*/
// 從ClientConnectionManager擷取串連的時間,這是從串連池中擷取串連的逾時設定,只有在串連池所有串連都在使用的情況下才可能出現逾時。逾時會扔出ConnectionPoolTimeoutException。一個HttpClient對應管理器,有串連池,裡面有多個串連(socket),這是我對其架構的猜測。
ConnManagerParams.setTimeout(params, 1000);
// 這是串連到遠端web server的逾時設定,逾時會扔出ConnectTimeoutException
HttpConnectionParams.setConnectionTimeout(params, 5000);//連線逾時
// 這是發送請求訊息後,最多等待多長時間得到響應的設定,逾時會扔出SocketTimeoutException
HttpConnectionParams.setSoTimeout(params, 10000);//socket逾時
//【2.2】設定Sheme,註冊了http和https
SchemeRegistry schReg = new SchemeRegistry();
schReg.register(new Scheme("http",PlainSocketFactory.getSocketFactory(), 80));
schReg.register(new Scheme("https",PlainSocketFactory.getSocketFactory(), 443));
//【2】ClientConnectionManager用於管理HTTP串連,我們使用同一個client來處理請求,要確保多線程的使用安全,採用ThreadSafeClientConnManager,是安全執行緒的串連池。如果多個線程同時請求,或有延遲情況。
ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params,schReg);
//【1】以ThreadSafeClientConnManager為管理器參數,建立可進行多線程調用的同步保護的HttpClient對象
client = new DefaultHttpClient(conMgr,params);
使用共用HttpClient對象的代碼基礎代碼
下面給出Activity調用這個共用的HttpClient的代碼:
public class HttpActivity extends Activity{
private HttpClient client = null;
protected void onCreate(Bundle savedInstanceState) {
…… //UI處理等
client = CustomHttpClient.getCustomHttpClient();
getHttpContent();
}
private void getHttpContent(){
try{
HttpGet request = new HttpGet("http://www.google.com");
/* 在處理response時,利用Android提供的BasicResponseHandler:handleResponse(HttpResponse response),Returns the response body as a String. if the response was successful (a 2xx status code). */
String page = client.execute(request,new BasicResponseHandler());
Log.d("PRO-HTTP",page);
}catch(IOException e){
e.printStackTrace();
}
}
}
修改HTTP串連的參數
我們在建立HttpClient時已經設定了有關的HTTP串連參數,實際對應的是HTTP請求訊息中的訊息頭,如果某個請求需要對這些參數進行修改,不應對公用屬性進行修改,否則會影響到其他請求,而是通過對具體的request請求進行設定。代碼例子如下:
// 我們設定了內部網的一個空地址,通過LogCat中連線逾時出現的時間,來判斷參數修改是否成功
HttpGet request = new HttpGet("http://192.168.0.199");
// 讀取httpClient的參數設定
HttpParams clientParams=client.getParams();
Log.d("PRO-HTTP",Log.d(String.valueOf(HttpConnectionParams.getConnectionTimeout(clientParams)));//顯示為5000
Log.d("PRO-HTTP",String.valueOf(HttpConnectionParams.getSoTimeout(clientParams)));//顯示為10000
// 原來設定的連線逾時是5秒,下面將重新設定該參數,設為20秒,我們將新的參數設定在request中,將不影響其他的請求
HttpParams params = request.getParams();
HttpConnectionParams.setConnectionTimeout(params, 20000);//20s
request.setParams(params);
Log.d("PRO-HTTP",String.valueOf(HttpConnectionParams.getConnectionTimeout(params)));//顯示20000
Log.d("PRO-HTTP",String.valueOf(HttpConnectionParams.getSoTimeout(params))); //顯示0
使用共同的Appcliation對象
對於應用全域共用同一對象,使人想起appclication對象,對於Android應用,都會有一個application對象,在在應用中可以通過getApplicationContext()或者getApplication()來獲得。如果我們沒有自訂的Application類,就是用android.app.Application。我們當然也可以將HttpClient對象放置在自訂的application類,但是為了這點小事來是Application類變得複雜並不可取。
在此,我們將探討自訂的Appcliation。很簡單,只要建立自訂的Application類即可,至於application對象的建立,均有系統來完成。下面我們在自訂的Application中加入一個計數器。
import android.app.Application;
public class CustomApplication extends Application{
private int counter = 0;
public int getCounter(){
return ++counter;
}
}
在應用的所有組件都都可以application對象,且是唯一的一個。從運行結果看出,獲得這個對象有好幾種方式。
CustomApplication app = (CustomApplication)getApplication();
Log.d("PRO-wei","counter: " + app.getCounter()); //測試一下計數器是否正常
Log.d("PRO-wei","context: " + app);
Log.d("PRO-wei","context: " + app.getApplicationContext()); //測試一下獲得app類的其他方式
Log.d("PRO-wei","context: " + getApplicationContext()); //測試一下獲得app類的其他方式
本博文涉及的例子代碼,可以在Pro Android學習:Http service小例子中下載。
相關連結: 我的Android開發相關文章
【轉】 Pro Android學習筆記(七一):HTTP服務(5):多線程調用HttpClient