Android网络(4):HttpClient必经之路----使用线程安全的单例模式HttpClient,及HttpClient和Application

来源:互联网 发布:批量部署windows 编辑:程序博客网 时间:2024/06/05 18:05
上文简单介绍了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"

    <application  android:name="org.yanzi.application.MyApplication"  android:allowBackup="true"  android:icon="@drawable/ic_launcher"  android:label="@string/app_name"  android:theme="@style/AppTheme" >  <activity      android:name="org.yanzi.testtomecat.MainActivity"      android:label="@string/app_name" >      <intent-filter>    <action android:name="android.intent.action.MAIN" />    <category android:name="android.intent.category.LAUNCHER" />      </intent-filter>  </activity>    </application>
0 0
原创粉丝点击