首页 > 代码库 > ndroid网络(4):HttpClient必经之路----使用线程安全的单例模式HttpClient,及HttpClient和Application的融合

ndroid网络(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 来完成。下面贴出完整代码:

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.webutil;  
  2.   
  3. import org.apache.http.HttpVersion;  
  4. import org.apache.http.client.HttpClient;  
  5. import org.apache.http.conn.ClientConnectionManager;  
  6. import org.apache.http.conn.params.ConnManagerParams;  
  7. import org.apache.http.conn.scheme.PlainSocketFactory;  
  8. import org.apache.http.conn.scheme.Scheme;  
  9. import org.apache.http.conn.scheme.SchemeRegistry;  
  10. import org.apache.http.conn.ssl.SSLSocketFactory;  
  11. import org.apache.http.impl.client.DefaultHttpClient;  
  12. import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;  
  13. import org.apache.http.params.BasicHttpParams;  
  14. import org.apache.http.params.HttpConnectionParams;  
  15. import org.apache.http.params.HttpParams;  
  16. import org.apache.http.params.HttpProtocolParams;  
  17. import org.apache.http.protocol.HTTP;  
  18.   
  19. public class MyHttpClient {  
  20.     private static HttpClient mHttpClient = null;  
  21.     private static final String CHARSET = HTTP.UTF_8;  
  22.     //将构造函数封掉,只能通过对外接口来获取HttpClient实例  
  23.     private MyHttpClient(){  
  24.   
  25.     }  
  26.     public static HttpClient getHttpClient(){  
  27.         if(mHttpClient == null){  
  28.             mHttpClient = new DefaultHttpClient();  
  29.         }  
  30.         return mHttpClient;  
  31.     }  
  32.     public static synchronized HttpClient getSaveHttpClient(){  
  33.         if(mHttpClient == null){  
  34.             HttpParams params = new BasicHttpParams();  
  35.             //设置基本参数  
  36.             HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);  
  37.             HttpProtocolParams.setContentCharset(params, CHARSET);  
  38.             HttpProtocolParams.setUseExpectContinue(params, true);  
  39.             //超时设置  
  40.             /*从连接池中取连接的超时时间*/  
  41.             ConnManagerParams.setTimeout(params, 1000);  
  42.             /*连接超时*/  
  43.             HttpConnectionParams.setConnectionTimeout(params, 2000);  
  44.             /*请求超时*/  
  45.             HttpConnectionParams.setSoTimeout(params, 4000);  
  46.             //设置HttpClient支持HTTp和HTTPS两种模式  
  47.             SchemeRegistry schReg = new SchemeRegistry();  
  48.             schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));  
  49.             schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));  
  50.             //使用线程安全的连接管理来创建HttpClient  
  51.             ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params, schReg);  
  52.             mHttpClient = new DefaultHttpClient(conMgr, params);  
  53.         }  
  54.         return mHttpClient;  
  55.     }  
  56.       
  57. }  
  58. </span>  


方法getSaveHttpClient()即可获得线程安全的单例httpClient,注释很详细了啥都不说了,可以直接使用。

3、已经很完美了,还能不能再优化呢? 

可以使用Application来进一步优化创建HttpClient的时机及其他配置。Application的相关知识参见:链接 

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

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.application;  
  2.   
  3. import org.apache.http.HttpVersion;  
  4. import org.apache.http.client.HttpClient;  
  5. import org.apache.http.conn.ClientConnectionManager;  
  6. import org.apache.http.conn.params.ConnManagerParams;  
  7. import org.apache.http.conn.scheme.PlainSocketFactory;  
  8. import org.apache.http.conn.scheme.Scheme;  
  9. import org.apache.http.conn.scheme.SchemeRegistry;  
  10. import org.apache.http.conn.ssl.SSLSocketFactory;  
  11. import org.apache.http.impl.client.DefaultHttpClient;  
  12. import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;  
  13. import org.apache.http.params.BasicHttpParams;  
  14. import org.apache.http.params.HttpConnectionParams;  
  15. import org.apache.http.params.HttpParams;  
  16. import org.apache.http.params.HttpProtocolParams;  
  17. import org.apache.http.protocol.HTTP;  
  18.   
  19. import android.app.Application;  
  20.   
  21. public class MyApplication extends Application {  
  22.     private HttpClient mHttpClient = null;  
  23.     private static final String CHARSET = HTTP.UTF_8;  
  24.     @Override  
  25.     public void onCreate() {  
  26.         // TODO Auto-generated method stub  
  27.         super.onCreate();  
  28.         mHttpClient = this.createHttpClient();  
  29.     }  
  30.   
  31.     @Override  
  32.     public void onTerminate() {  
  33.         // TODO Auto-generated method stub  
  34.         super.onTerminate();  
  35.         this.shutdownHttpClient();  
  36.     }  
  37.   
  38.     @Override  
  39.     public void onLowMemory() {  
  40.         // TODO Auto-generated method stub  
  41.         super.onLowMemory();  
  42.         this.shutdownHttpClient();  
  43.     }  
  44.       
  45.     /**创建HttpClient实例 
  46.      * @return 
  47.      */  
  48.     private HttpClient createHttpClient(){  
  49.         HttpParams params = new BasicHttpParams();  
  50.         //设置基本参数  
  51.         HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);  
  52.         HttpProtocolParams.setContentCharset(params, CHARSET);  
  53.         HttpProtocolParams.setUseExpectContinue(params, true);  
  54.         //超时设置  
  55.         /*从连接池中取连接的超时时间*/  
  56.         ConnManagerParams.setTimeout(params, 1000);  
  57.         /*连接超时*/  
  58.         HttpConnectionParams.setConnectionTimeout(params, 2000);  
  59.         /*请求超时*/  
  60.         HttpConnectionParams.setSoTimeout(params, 4000);  
  61.         //设置HttpClient支持HTTp和HTTPS两种模式  
  62.         SchemeRegistry schReg = new SchemeRegistry();  
  63.         schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));  
  64.         schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));  
  65.         //使用线程安全的连接管理来创建HttpClient  
  66.         ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params, schReg);  
  67.         HttpClient client = new DefaultHttpClient(conMgr, params);  
  68.         return client;  
  69.     }  
  70.     private void shutdownHttpClient(){  
  71.         if(mHttpClient != null && mHttpClient.getConnectionManager() != null){  
  72.             mHttpClient.getConnectionManager().shutdown();  
  73.         }  
  74.     }  
  75.     public HttpClient getHttpClient(){  
  76.         return mHttpClient;  
  77.     }  
  78.   
  79. }  
  80. </span>  


然后再AndroidManifest.xml理添加:

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

[html] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. <span style="font-family:Comic Sans MS;font-size:18px;">    <application  
  2.         android:name="org.yanzi.application.MyApplication"  
  3.         android:allowBackup="true"  
  4.         android:icon="@drawable/ic_launcher"  
  5.         android:label="@string/app_name"  
  6.         android:theme="@style/AppTheme" >  
  7.         <activity  
  8.             android:name="org.yanzi.testtomecat.MainActivity"  
  9.             android:label="@string/app_name" >  
  10.             <intent-filter>  
  11.                 <action android:name="android.intent.action.MAIN" />  
  12.   
  13.                 <category android:name="android.intent.category.LAUNCHER" />  
  14.             </intent-filter>  
  15.         </activity>  
  16.     </application></span>  


然后再Activity里,通过mMyApplication = (MyApplication)getApplication();

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

可以看到在Application的onCreate里就实例化了HttpClient,且在低内存和关闭时关闭连接管理器,释放资源,比2中的写到一个普通文件里更优。