上文简 单介绍了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. Oracle11G安装

    1.安装Oracle 记住要设置好密码 不要忘了 解锁scott(注意一定要解锁)账户, 去掉前面的绿色小勾,输入密码.同样可以输入平常用的短小的密码,不必非得按oracle建议的8位以上大小写加数字 ...

  2. jQuery图片滑动

    一个非常简单实用的jQuery插件 可以用在页面的顶部广告展示 http://slidesjs.com/ 一个需要注意的问题, 就是在手机等客户端(IOS8以上), 使用此插件时, 经常会触发插件的r ...

  3. 【转载】如何学习javascript

    如何学习Javascript 作者: chaomao  首先要说明的是,咱现在不是高手,最多还是一个半桶水,算是入了JS的门. 谈不上经验,都是一些教训. 这个时候有人要说,“靠,你丫半桶水,凭啥教我 ...

  4. Linq介绍

    什么是LINQ? LINQ全称Language Integrated Query,中文翻译"语言集成查询".在.NET框架中,大致使用三大组件实现这个封装,分别 LINQ to O ...

  5. STL容器介绍

    STL的容器可以分为以下几个大类: 一:序列容器, 有vector, list, deque, string. 二 : 关联容器,     有set, multiset, map, mulmap, h ...

  6. linux c数据库备份第四版

    该版本算是比较成熟的啦,欢迎大伙拿来试用!!!1.新增数据库连接和备份时间配置文件conf2.新增日志文件,程序运行的一些异常会记录在log文件下 后续的工作:1.将代码切割为多个文件,分类存放代码2 ...

  7. python的sorted相关

    Python 字典排序 在python里,字典是内置的数据类型,是个无序的存储结构,每一个元素是key-value对: 有关key的解释: sorted(L,key=by_name)中的key即by_ ...

  8. NET Core 数据保护2

    ASP.NET Core 数据保护(Data Protection 集群场景)[下]   前言 接[中篇],在有一些场景下,我们需要对 ASP.NET Core 的加密方法进行扩展,来适应我们的需求, ...

  9. 【转】Windows平台下Git服务器搭建

    Windows平台下Git服务器搭建 Posted on 2015-05-18 21:29 阿祥当码农 阅读(7637) 评论(0) 编辑 收藏 该文章转自:http://www.codeceo.co ...

  10. Solr4.8.0源码分析(16)之SolrCloud索引深入(3)

    Solr4.8.0源码分析(16)之SolrCloud索引深入(3) 前面两节学习了SolrCloud索引过程以及索引链的前两步,LogUpdateProcessorFactory和Distribut ...