上文简 单介绍了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 来完成。下面贴出完整代码:

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

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

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

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

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

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

然后再AndroidManifest.xml理添加:

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

  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. <category android:name="android.intent.category.LAUNCHER" />
  13. </intent-filter>
  14. </activity>
  15. </application></span>

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

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

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

ndroid网络(4):HttpClient必经之路----使用线程安全的单例模式HttpClient,及HttpClient和Application的融合的更多相关文章

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

    上文简介了HttpClient和Tomcatserver的交互,主角是HttpClient,然后它跟server交互有两种方式即get和post.所以这个HttpClient就相似于电脑上用的浏览器. ...

  2. 网络请求怎么样和UI线程交互? Activity2怎么通知Activity1 更新数据

    1.网络请求怎么样和UI线程交互? 目前我的做法是,建立线程池管理网络请求线程,通过添加task来新增网络请求.所有的网络操作通过统一的request来实现,网络返回结果通过回调onError和onS ...

  3. muduo网络库源码学习————线程安全

    线程安全使用单例模式,保证了每次只创建单个对象,代码如下: Singleton.h // Use of this source code is governed by a BSD-style lice ...

  4. java多线程(一)——线程安全的单例模式

    概念: java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例.饿汉式单例.登记式单例三种. 单例模式有一下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3. ...

  5. Android之线程安全的单例模式,Adapter注意事项之引用传值

    线程安全的单例模式单位模式一般写法如下: public static FestivalLab mInstance; private FestivalLab() { } public static Fe ...

  6. 线程安全的单例模式还需要对成员变量的set get方法设置锁么

    不需要,线程安全的单例模式,在获得对象时已经加锁了,保证每时每刻只有一个线程获得此单例对象.所以不需要再上锁了啊

  7. 【多线程那些事儿】如何使用C++写一个线程安全的单例模式?

    如何写一个线程安全的单例模式? 单例模式的简单实现 单例模式大概是流传最为广泛的设计模式之一了.一份简单的实现代码大概是下面这个样子的: class singleton { public: stati ...

  8. 从零开始构建一个Reactor模式的网络库(二)线程类Thread

    线程类Thread是对POSIX线程的封装类,因为要构建的是一个Linux环境下的多线程网络库,对线程的封装是很必要的. 首先是CurrentThread命名空间,主要是获取以及缓存线程id: #if ...

  9. 从零开始构建一个Reactor模式的网络库(一) 线程同步Mutex和Condition

    最近在学习陈硕大神的muduo库,感觉写的很专业,以及有一些比较“高级”的技巧和设计方式,自己写会比较困难. 于是打算自己写一个简化版本的Reactor模式网络库,就取名叫mini吧,同样只基于Lin ...

随机推荐

  1. PHP MySQL 创建数据库

    PHP MySQL 创建数据库 数据库存有一个或多个表. 你需要 CREATE 权限来创建或删除 MySQL 数据库. 使用 MySQLi 和 PDO 创建 MySQL 数据库 CREATE DATA ...

  2. mysql操作1

    一.连接MYSQL.格式: mysql -h主机地址 -u用户名 -p用户密码1.连接到本机上的MYSQL.首先打开DOS窗口,然后进入目录mysql\bin,再键入命令mysql -u root - ...

  3. php解析json数据

    <?php $data; $data.="["; for ($i=0;$i<20;$i++) { $data.="{"; $data.=" ...

  4. location对象,将url解析为独立片段search属性截取传递的参数

    通过location对象的search属性截取字符串传递过来的参数 search ?item=hello&name=auto&age=25 返回url中传递的参数,以?开头 funct ...

  5. 在sublimetext上打造一个兼容virtualenv的web&python开发环境

    利用Sublimetext3&virtualenv 打造一个Web&Python IDE 注: 环境:window|python3;以下使用的sublimetext插件均用packag ...

  6. 外卖的撕‘哔’大战 CSU 1559

                                                      CSU 1559 Time Limit:1000MS     Memory Limit:131072 ...

  7. bzoj4171 or 省队集训day3 chess: Rhl的游戏

    [题目描述] RHL最近迷上一个小游戏:Flip it.游戏的规则很简单,在一个N*M的格子上,有一些格子是黑色,有一些是白色.每选择一个格子按一次,格子以及周围边相邻的格子都会翻转颜色(边相邻指至少 ...

  8. JS之路——浏览器window对象

    window对象的方法 window.alert(msg) window.close() window.print() var a = window.setIntval(function,毫秒) // ...

  9. Delphi图像处理控件

    Envision Image Library (Full Sources for D7 to D10-Seattle) v3.08http://www.intervalsoftware.com/env ...

  10. C++ 常用的字符串处理函数实现

    以下是一些标准库没有实现的函数,我觉得很方便就写了,估计会不定时更新. //根据一个文件的路径获取文件名 std::string file_name(const std::string& pa ...