Android網絡(4):HttpClient必經之路—-使用線程安全的單例模式HttpClient,及HttpClient和Application的融合

上文簡單介紹瞭HttpClient和Tomcat服務器的交互,主角是HttpClient,然後它跟服務器交互有兩種方式即get和post。所以這個HttpClient就類似於電腦上用的瀏覽器。當我打開多個網頁的時候,並不需要開一個網頁就開一個瀏覽器,而是一個瀏覽器上面開瞭好幾個網頁。對應於HttpClient,即無需連接一次就new一個HttpClient。一般,我們希望一個應用裡就一個HttpClient就ok瞭,就像我們的手機或PC,沒人會呼呼的裝好幾個瀏覽器。本文即解決此問題,代碼可以直接拿過去復用。

1、自然而然想到單例。

public class MyHttpClient {
private static HttpClient mHttpClient = null;
private static final String CHARSET = HTTP.UTF_8;
//將構造函數封掉,隻能通過對外接口來獲取HttpClient實例
private MyHttpClient(){

}
public static HttpClient getHttpClient(){
if(mHttpClient == null){
mHttpClient = new DefaultHttpClient();
}
return mHttpClient;
}
}

上面是最簡單的一種單例,確實能夠滿足需要。但不能滿足多線程的要求,即當同時完成多個Http請求時,就出馬蛋瞭。

2、線程安全的HttpClient

幸運的是android已經提供瞭可以創建線程安全的HttpClient,即通過ClientConnectionManager 來完成。下面貼出完整代碼:

package org.yanzi.webutil;

import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;

public class MyHttpClient {
	private static HttpClient mHttpClient = null;
	private static final String CHARSET = HTTP.UTF_8;
	//將構造函數封掉,隻能通過對外接口來獲取HttpClient實例
	private MyHttpClient(){

	}
	public static HttpClient getHttpClient(){
		if(mHttpClient == null){
			mHttpClient = new DefaultHttpClient();
		}
		return mHttpClient;
	}
	public static synchronized HttpClient getSaveHttpClient(){
		if(mHttpClient == null){
			HttpParams params = new BasicHttpParams();
			//設置基本參數
			HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
			HttpProtocolParams.setContentCharset(params, CHARSET);
			HttpProtocolParams.setUseExpectContinue(params, true);
			//超時設置
			/*從連接池中取連接的超時時間*/
			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);
			mHttpClient = new DefaultHttpClient(conMgr, params);
		}
		return mHttpClient;
	}
	
}

方法getSaveHttpClient()即可獲得線程安全的單例httpClient,註釋很詳細瞭啥都不說瞭,可以直接使用。

3、已經很完美瞭,還能不能再優化呢?

可以使用Application來進一步優化創建HttpClient的時機及其他配置。Application的相關知識參見:鏈接

新建包名org.yanzi.application,在裡面新建MyApplication.java,完整代碼如下:

package org.yanzi.application;

import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;

import android.app.Application;

public class MyApplication extends Application {
	private HttpClient mHttpClient = null;
	private static final String CHARSET = HTTP.UTF_8;
	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		mHttpClient = this.createHttpClient();
	}

	@Override
	public void onTerminate() {
		// TODO Auto-generated method stub
		super.onTerminate();
		this.shutdownHttpClient();
	}

	@Override
	public void onLowMemory() {
		// TODO Auto-generated method stub
		super.onLowMemory();
		this.shutdownHttpClient();
	}
	
	/**創建HttpClient實例
	 * @return
	 */
	private HttpClient createHttpClient(){
		HttpParams params = new BasicHttpParams();
		//設置基本參數
		HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
		HttpProtocolParams.setContentCharset(params, CHARSET);
		HttpProtocolParams.setUseExpectContinue(params, true);
		//超時設置
		/*從連接池中取連接的超時時間*/
		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);
		HttpClient client = new DefaultHttpClient(conMgr, params);
		return client;
	}
	private void shutdownHttpClient(){
		if(mHttpClient != null && mHttpClient.getConnectionManager() != null){
			mHttpClient.getConnectionManager().shutdown();
		}
	}
	public HttpClient getHttpClient(){
		return mHttpClient;
	}

}

然後再AndroidManifest.xml理添加:

android:name=”org.yanzi.application.MyApplication”

    
        
            
                

                
            
        
    

然後再Activity裡,通過mMyApplication = (MyApplication)getApplication();

mMyApplication.getHttpClient()得到HttpClient就可以使用瞭。

可以看到在Application的onCreate裡就實例化瞭HttpClient,且在低內存和關閉時關閉連接管理器,釋放資源,比2中的寫到一個普通文件裡更優。

You May Also Like