Android平台有三种网络接口可以使用,他们分别是:java.net.*(标准Java接口)、Org.apache接口和Android.net.*(Android网络接口)。大多数的Android应用程序都会使用HTTP协议来发送和接收网络数据,而Android中主要提供了两种方式来进行HTTP操作,HttpURLConnection和HttpClient。这两种方式都支持HTTPS协议、以流的形式进行上传和下载、配置超时时间、IPv6、以及连接池等功能。
1.标准Java接口
java.net.*提供与联网有关的类,包括流、数据包套接字(socket)、Internet协议、常见Http处理等。比如:创建URL,以及URLConnection/HttpURLConnection对象、设置链接参数、链接到服务器、向服务器写数据、从服务器读取数据等通信。这些在Java网络编程中均有涉及,我们看一个简单的socket编程,实现服务器回发客户端信息。

java.net包中的HttpURLConnection类

开发文档描述http://developer.android.com/reference/java/net/HttpURLConnection.html

httpURLConnection是一种多用途、轻量极的HTTP客户端,使用它来进行HTTP操作可以适用于大多数的应用程序。虽然HttpURLConnection的API提供的比较简单,但是同时这也使得我们可以更加容易地去使用和扩展它。

下面看看一些存在问题

1.在Android 2.2版本之前,HttpURLConnection一直存在着一些令人厌烦的bug。比如说对一个可读的InputStream调用close()方法时,就有可能会导致连接池失效了。那么我们通常的解决办法就是直接禁用掉连接池的功能:

private void disableConnectionReuseIfNecessary() {
// 这是一个2.2版本之前的bug
if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
System.setProperty("http.keepAlive", "false");
}
}

2.HttpURLConnection.getContentLength()大小问题

HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.connect();
int length = conn.getContentLength();
InputStream is = conn.getInputStream();

在Android 2.2版本之前,如果服务端没有设content length,conn.getContentLength() 时获取到的值为 -1。

3.gzip压缩文件大小改变问题

在Android 2.3版本的时候,更加透明化的响应压缩。HttpURLConnection会自动在每个发出的请求中加入如下消息头,并处理相应的返回结果:Accept-Encoding: gzip。使用 gzip方式压缩,HTTP响应头里的Content-Length就会代表着压缩后的长度,这时再使用getContentLength()方法来取出解压后的数据就是错误的了,如果这个是需要做下载进度的话可能会出问题,可以加上这句话来要求http请求不要gzip压缩

 urlConnection.setRequestProperty("Accept-Encoding", "identity");

我们在Android 2.3版本中还增加了一些HTTPS方面的改进,现在HttpsURLConnection会使用SNI(Server Name Indication)的方式进行连接,使得多个HTTPS主机可以共享同一个IP地址。除此之外,还增加了一些压缩和会话的机制。如果连接失败,它会自动去尝试重新进行连接。这使得HttpsURLConnection可以在不破坏老版本兼容性的前提下,更加高效地连接最新的服务器。

4.HttpURLConnection上传大的文件的时候会容易内存溢出

在这片文章里面有介绍http://www.mzone.cc/article/198.html

5.链接超时问题

HttpURLConnection是基于HTTP协议的,其底层通过socket通信实现。如果不设置超时(timeout),在网络异常的情况下,可能会导致程序僵死而不继续往下执行。可以使用HttpURLConnection的父类URLConnection的以下两个方法:
setConnectTimeout:设置连接主机超时(单位:毫秒)
setReadTimeout:设置从主机读取数据超时(单位:毫秒)

HttpURLConnection urlCon = (HttpURLConnection)url.openConnection();
urlCon.setConnectTimeout(30000);
urlCon.setReadTimeout(30000);

新增功能

 1。在Android 4.0版本中,我们又添加了一些响应的缓存机制。

在Ice Cream Sandwich(4.0),增加了response cache。安装了cache后,当缓存被安装后(调用HttpResponseCache的install()方法),所有的HTTP请求都会满足以下三种情况:

  • 所有的缓存响应都由本地存储来提供。因为没有必要去发起任务的网络连接请求,所有的响应都可以立刻获取到。
  • 视情况而定的缓存响应必须要有服务器来进行更新检查。比如说客户端发起了一条类似于 “如果/foo.png这张图片发生了改变,就将它发送给我” 这样的请求,服务器需要将更新后的数据进行返回,或者返回一个304 Not Modified状态。如果请求的内容没有发生,客户端就不会下载任何数据。
  • 没有缓存的响应都是由服务器直接提供的。这部分响应会在稍后存储到响应缓存中。

由于这个功能是在4.0之后的版本才有的,通常我们就可以使用反射的方式来启动响应缓存功能。下面的示例代码展示了如何在Android 4.0及以后的版本中去启用响应缓存的功能,同时还不会影响到之前的版本:

private void enableHttpResponseCache() {
try {
long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
File httpCacheDir = new File(getCacheDir(), "http");
Class.forName("android.net.http.HttpResponseCache")
.getMethod("install", File.class, long.class)
.invoke(null, httpCacheDir, httpCacheSize);
} catch (Exception httpResponseCacheNotAvailable) {
}
}

你也应该同时配置一下你的Web服务器,在HTTP响应上加入缓存的消息头。

下面看看使用方法

Get方式:

public static void requestByGet() throws Exception {
String path = "https://reg.163.com/logins.jsp?id=helloworld&pwd=android";
// 新建一个URL对象
URL url = new URL(path);
// 打开一个HttpURLConnection连接
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
// 设置连接超时时间
urlConn.setConnectTimeout(5 * 1000);
// 开始连接
urlConn.connect();
// 判断请求是否成功
if (urlConn.getResponseCode() == HTTP_200) {
// 获取返回的数据
byte[] data = readStream(urlConn.getInputStream());
Log.i(TAG_GET, "Get方式请求成功,返回数据如下:");
Log.i(TAG_GET, new String(data, "UTF-8"));
} else {
Log.i(TAG_GET, "Get方式请求失败");
}
// 关闭连接
urlConn.disconnect();
}

Post方式:

// Post方式请求
public static void requestByPost() throws Throwable {
String path = "https://reg.163.com/logins.jsp";
// 请求的参数转换为byte数组
String params = "id=" + URLEncoder.encode("helloworld", "UTF-8")
+ "&pwd=" + URLEncoder.encode("android", "UTF-8");
byte[] postData = params.getBytes();
// 新建一个URL对象
URL url = new URL(path);
// 打开一个HttpURLConnection连接
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
// 设置连接超时时间
urlConn.setConnectTimeout(5 * 1000);
// Post请求必须设置允许输出
urlConn.setDoOutput(true);
// Post请求不能使用缓存
urlConn.setUseCaches(false);
// 设置为Post请求
urlConn.setRequestMethod("POST");
urlConn.setInstanceFollowRedirects(true);
// 配置请求Content-Type
urlConn.setRequestProperty("Content-Type",
"application/x-www-form-urlencode");
// 开始连接
urlConn.connect();
// 发送请求参数
DataOutputStream dos = new DataOutputStream(urlConn.getOutputStream());
dos.write(postData);
dos.flush();
dos.close();
// 判断请求是否成功
if (urlConn.getResponseCode() == HTTP_200) {
// 获取返回的数据
byte[] data = readStream(urlConn.getInputStream());
Log.i(TAG_POST, "Post请求方式成功,返回数据如下:");
Log.i(TAG_POST, new String(data, "UTF-8"));
} else {
Log.i(TAG_POST, "Post方式请求失败");
}
}

2.Apache接口org.apache.http包中的HttpGet和HttpPost类
对于大部分应用程序而言JDK本身提供的网络功能已远远不够,这时就需要Android提供的Apache HttpClient了。它是一个开源项目,功能更加完善,为客户端的Http编程提供高效、最新、功能丰富的工具包支持。
在android SDK中httpclient使用的是4.0beta2,我不得不说这个版本里面有些蛋疼的bug:在4.0上的sdk,将wifi和3g同时打开,理论上来说,网络接口应该走wifi,但是却走了代理,导致访问服务器网络失败;

解决上面问题的办法就是引入“http://code.google.com/p/httpclientandroidlib/”中的库,然后修改相应的类,典型的例子就是ThreadSafeClientConnManager变成了PoolingClientConnectionManager。

下面看看使用方法

Get方式:

// HttpGet方式请求
public static void requestByHttpGet() throws Exception {
String path = "https://reg.163.com/logins.jsp?id=helloworld&pwd=android";
// 新建HttpGet对象
HttpGet httpGet = new HttpGet(path);
// 获取HttpClient对象
HttpClient httpClient = new DefaultHttpClient();
// 获取HttpResponse实例
HttpResponse httpResp = httpClient.execute(httpGet);
// 判断是够请求成功
if (httpResp.getStatusLine().getStatusCode() == HTTP_200) {
// 获取返回的数据
String result = EntityUtils.toString(httpResp.getEntity(), "UTF-8");
Log.i(TAG_HTTPGET, "HttpGet方式请求成功,返回数据如下:");
Log.i(TAG_HTTPGET, result);
} else {
Log.i(TAG_HTTPGET, "HttpGet方式请求失败");
}
}

Post方式:

// HttpPost方式请求
public static void requestByHttpPost() throws Exception {
String path = "https://reg.163.com/logins.jsp";
// 新建HttpPost对象
HttpPost httpPost = new HttpPost(path);
// Post参数
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("id", "helloworld"));
params.add(new BasicNameValuePair("pwd", "android"));
// 设置字符集
HttpEntity entity = new UrlEncodedFormEntity(params, HTTP.UTF_8);
// 设置参数实体
httpPost.setEntity(entity);
// 获取HttpClient对象
HttpClient httpClient = new DefaultHttpClient();
// 获取HttpResponse实例
HttpResponse httpResp = httpClient.execute(httpPost);
// 判断是够请求成功
if (httpResp.getStatusLine().getStatusCode() == HTTP_200) {
// 获取返回的数据
String result = EntityUtils.toString(httpResp.getEntity(), "UTF-8");
Log.i(TAG_HTTPGET, "HttpPost方式请求成功,返回数据如下:");
Log.i(TAG_HTTPGET, result);
} else {
Log.i(TAG_HTTPGET, "HttpPost方式请求失败");
}
}

关于安卓HTTP请求用HttpUrlConnection还是HttpClient好

安卓和JAVA应用开发少不了要提交HTTP请求,而基本上目前有两个实现方式:HttpUrlConnection(即URL.openConnection)和HttpClient。

网上不少人都认为HttpClient更好,理由是功能更强,BUG更少,更容易控制细节。但我个人认为普通JAVA人员可选用HttpClient,安卓开发人员则应该使用HttpUrlConnection,理由如下:

1.HttpClient是apache的开源实现,而HttpUrlConnection是安卓标准实现,安卓SDK虽然集成了HttpClient,但官方支持的却是HttpUrlConnection;

2. 2.3版本HttpUrlConnection直接支持GZIP压缩;HttpClient也支持,但要自己写代码处理;我们之前测试HttpUrlConnection的GZIP压缩在传大文件分包trunk时有问题,只适合小文件,不过这个BUG后来官方说已经修复了;

3.HttpUrlConnection直接支持系统级连接池,即打开的连接不会直接关闭,在一段时间内所有程序可共用;HttpClient当然也能做到,但毕竟不如官方直接系统底层支持好;

4.在4.0版本中HttpUrlConnection直接在系统层面做了缓存策略处理,加快重复请求的速度。

谷歌自己也是推荐用HttpUrlConnection,对它进行了大量的优化,这个从安卓的帮助文档可以看出来:

http://developer.android.com/reference/java/net/HttpURLConnection.html

安卓开发博客上也强调,2.2以后的安卓都应该用HttpUrlConnection(这个需要翻墙):

http://android-developers.blogspot.com/2011/09/androids-http-clients.html

总之,在安卓开发上,虽然HttpClient更好地支持很多细节的控制(如代理、COOKIE、鉴权、压缩、连接池),但相应地对开发人员要求更高,代码写起来更复杂,普通开发人员很难做到对它很好地驾驭,官方的支持也越来越少;而HttpUrlConnection对大部分工作进行了包装,屏蔽了不需要的细节,更适合开发人员直接调用,而且官方对它的支持和优化也会越来越好。我们既然是做安卓应用的开发,自然要遵循安卓官方的指引,选用HttpUrlConnection。

参考http://blog.csdn.net/guolin_blog/article/details/12452307

http://blog.csdn.net/huzgd/article/details/8712187

Android的网络通信的更多相关文章

  1. 详细讲解Android的网络通信(HttpUrlConnection和HttpClient)

    前言,Android的网络通信的方式有两种:使用Socket或者HTTP,今天这一篇我们详细讲解使用HTTP实现的网络通信,HTTP又包括两种方式编程方式: (1)HttpUrlConnection: ...

  2. android下网络通信流程

    新版本android中进行socket编程有了新的要求和规定,在主线程中不能进行socket的创建和通信.所以一般都在线程中使用socket编程 这样在线程中使用就需要出现子线程与主线程交互的问题. ...

  3. Android开发-网络通信2

    调试了三种通信方法:HttpClient.AsyncHttpClient 和 Volley . HttpClient 测试代码[1]: public class HttpUtil { public s ...

  4. Android开发-网络通信1

    使用 org.apache.http.client.HttpClient; 一开始从官网下载HttpClient 4.5:http://hc.apache.org/downloads.cgi ,解压之 ...

  5. Android的网络通信机制

    1. Socket接口 不常用 2.HttpURLConnection接口 3. HttpClient接口 http://blog.csdn.net/ccc20134/article/details/ ...

  6. 【Android】网络通信

    https://www.bilibili.com/video/av78497129?p=4 本文为此视频笔记 1.一些标准设定 (读头部和内容) --->运行,出现权限警告: --->运行 ...

  7. Android 网络通信API的选择和实现实例

    Android开发网络通信一开始的时候使用的是AsyncTask封装HttpClient,没有使用原生的HttpURLConnection就跳到了Volley,随着OkHttp的流行又开始迁移到OkH ...

  8. Java基础知识强化之网络编程笔记23:Android网络通信之 Volley(Google开源网络通信库)

    联合网上资料学习:http://www.open-open.com/lib/view/open1451223702339.html 一.Volley的介绍 1. Volley简介 在这之前,我们在程序 ...

  9. Android 学习笔记之ContentProvider实现数据共享....

    PS:最近听老师说打算让我参与企业的app制作,让我加快学习的进度...好吧,貌似下周还有考试...貌似实验室这个app也要做...暂时不管了...那就只能加快进度了,感觉略微的有点激动和紧张,总算是 ...

随机推荐

  1. MySQL读取各个my.cnf配置文件的先后顺序是:

    /etc/my.cnf /etc/mysql/my.cnf /usr/local/mysql/etc/my.cnf ~/.my.cnf 其他自定义路径下的my.cnf,例如:/data/mysql/y ...

  2. Hibernate Validator--创建自己的约束规则

    尽管Bean Validation API定义了一大堆标准的约束条件, 但是肯定还是有这些约束不能满足我们需求的时候, 在这种情况下, 你可以根据你的特定的校验需求来创建自己的约束条件. 3.1. 创 ...

  3. Django框架之第三篇模板语法

    一.什么是模板? 只要是在html里面有模板语法就不是html文件了,这样的文件就叫做模板. 二.模板语法分类 一.模板语法之变量:语法为 {{ }}: 在 Django 模板中遍历复杂数据结构的关键 ...

  4. 在vue项目中使用md5加密

    MD5:信息-摘要算法,是让大容量信息在用数字签名软件签署私人密匙前被"压缩"成一种保密的格式 一般我们把登录和注册信息的密码进行加密 1.安装模块 cnpm install js ...

  5. sharepoint Foundation 2013安装过程

    安装完必备软件后,便可安装sharepoint Foundation 2013

  6. 关于SCANF 与 GETS(C语言)

    SCANF遇到空格会自动停止录入字符串,而GETS不会,GETS可以用于输入带空格的字符串

  7. strstr strchr strrchr strrstr

    通过函数的定义来区分: 1.strstr: 返回子串出现的第一次位置 char *strstr(const char *haystack, const char *needle) 可见,strstr函 ...

  8. linux 环境变量恢复默认值

    export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin 在linux命令下如何访问一个ur ...

  9. JavaScript学习系列7 -- JavaScript中的运算符

    今天,我们来说一说JavaScript中的运算符,首先我们来讲一讲 一元运算符 JavaScript中的一元运算符有以下几种 1. delete delete 运算符主要用于删除对以前定义的对象属性或 ...

  10. Android Market google play store帐号注册方法流程 及发布应用注意事项

    Android Market google play store帐号申请 注册方法流程 在 Google Play 中发布软件之前,您需要完成以下三项工作: 创建开发人员个人资料 接受开发人员分发协议 ...