Android网络编程随想录(3)
大多数Android的app都会使用HTTP协议来发送和接收数据。在Android开发中,通常使用两种http客户端:一个是Apache的HttpClient,另一个是HttpURLConnection。这两种HTTP客户端API都支持HTTPS协议,流数据上传和下载,配置超时,IPV6协议以及连接池等等。
Apache HttpClient
HttpClient的API众多,并且bug少比较稳定。但是,HttpClient的API比较大,很难在保证兼容性的前提下去对其进行扩展。所以很多Android团队并不太喜欢使用它。HttpClient是一个接口,里面封装了需要执行的http请求,身份验证,连接管理等等,有三个主要的实现类:AbstractHttpClient, AndroidHttpClient, DefaultHttpClient。下面我们来看一下AndroidHttpClient,它对DefaultHttpClient进行了改进使之更适合于Android开发。于是,AndroidHttpClient进行请求发送和响应接收步骤如下:
- 创建HttpClient对象,通过静态方法newInstance()方法来获得AndroidHttpClient对象。
- 创建对应的发送请求的对象,如果需要发送GET请求,则创建HttpGet对象,如果需要发送POST请求,则创建HttpPost对象。
- 对于发送请求的参数,GET和POST使用的方式不同,GET方式可以使用拼接字符串的方式,把参数拼接在URL结尾;POST方式需要使用setEntity(HttpEntity entity)方法来设置请求参数。
- 调用HttpClient对象的execute(HttpUriRequest request)发送请求,执行该方法返回一个HttpResponse对象。
- 调用HttpResponse的对应方法获取服务器的响应头、响应内容等。
通常情况下,我们并不在主线程中进行网络请求操作,而是新开一个子线程来进行网络操作,下面的代码展示了如何利用AndroidHttpClient完成网络登录验证的任务:
public class LoginTask implements Runnable { private String username;
private String password; public LoginTask(String username, String password) {
// 初始化用户名和密码
this.username = username;
this.password = password;
} @Override
public void run() {
// 设置访问的Web站点
String path = "http://xxxx/loginas.aspx";
//设置Http请求参数
Map<String, String> params = new HashMap<String, String>();
params.put("username", username);
params.put("password", password); String result = sendHttpClientPost(path, params, "utf-8");
//把返回的接口输出
System.out.println(result);
}
/**
* 发送Http请求到Web站点
* @param path Web站点请求地址
* @param map Http请求参数
* @param encode 编码格式
* @return Web站点响应的字符串
*/
private String sendHttpClientPost(String path,Map<String, String> map,String encode)
{
List<NameValuePair> list=new ArrayList<NameValuePair>();
if(map!=null&&!map.isEmpty())
{
for(Map.Entry<String, String> entry:map.entrySet())
{
//解析Map传递的参数,使用一个键值对对象BasicNameValuePair保存。
list.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
}
try {
//实现将请求 的参数封装封装到HttpEntity中。
UrlEncodedFormEntity entity=new UrlEncodedFormEntity(list, encode);
//使用HttpPost请求方式
HttpPost httpPost=new HttpPost(path);
//设置请求参数到Form中。
httpPost.setEntity(entity);
//实例化一个默认的Http客户端,使用的是AndroidHttpClient
HttpClient client=AndroidHttpClient.newInstance("");
//执行请求,并获得响应数据
HttpResponse httpResponse= client.execute(httpPost);
//判断是否请求成功,为200时表示成功,其他均问有问题。
if(httpResponse.getStatusLine().getStatusCode()==200)
{
//通过HttpEntity获得响应流
InputStream inputStream=httpResponse.getEntity().getContent();
return changeInputStream(inputStream,encode);
} } catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} return "";
}
/**
* 把Web站点返回的响应流转换为字符串格式
* @param inputStream 响应流
* @param encode 编码格式
* @return 转换后的字符串
*/
private String changeInputStream(InputStream inputStream,
String encode) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int len = 0;
String result="";
if (inputStream != null) {
try {
while ((len = inputStream.read(data)) != -1) {
outputStream.write(data,0,len);
}
result=new String(outputStream.toByteArray(),encode); } catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
}
HttpURLConnection
相比之下,HttpURLConnection就显得更通用一些。它是一款多用途,轻量级的HTTP客户端,适用于大多数的app客户端。同时,HttpURLConnection简单,便于扩展。但是坑爹的是,在Android2.2之前,HttpURLConnection有一些bug,例如在试图关闭InputStream的时候会导致连接池失效。所以,推荐在2.3之后的版本中使用HttpURLConnection。
下面以请求百度首页的logo为例子,演示使用HttpURLConnection的GET方法完成网络请求的任务:
public class getImageTask{
private static String URL_PATH = http://www.baidu.com/img/bd_logo1.png;
/**
* @param args
*/
public static void main(String[] args) {
// 调用方法获取图片并保存
saveImageToDisk();
}
/**
* 通过URL_PATH的地址访问图片并保存到本地
*/
public static void saveImageToDisk()
{
InputStream inputStream= getInputStream();
byte[] data=new byte[1024];
int len=0;
FileOutputStream fileOutputStream=null;
try {
//把图片文件保存在本地F盘下
fileOutputStream=new FileOutputStream("F:\\test.png");
while((len=inputStream.read(data))!=-1)
{
//向本地文件中写入图片流
fileOutputStream.write(data,0,len);
}
} catch (IOException e) {
e.printStackTrace();
}
finally
{
//最后关闭流
if(inputStream!=null)
{
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fileOutputStream!=null)
{
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 通过URL获取图片
* @return URL地址图片的输入流。
*/
public static InputStream getInputStream() {
InputStream inputStream = null;
HttpURLConnection httpURLConnection = null; try {
//根据URL地址实例化一个URL对象,用于创建HttpURLConnection对象。
URL url = new URL(URL_PATH); if (url != null) {
//openConnection获得当前URL的连接
httpURLConnection = (HttpURLConnection) url.openConnection();
//设置3秒的响应超时
httpURLConnection.setConnectTimeout(3000);
//设置允许输入
httpURLConnection.setDoInput(true);
//设置为GET方式请求数据
httpURLConnection.setRequestMethod("GET");
//获取连接响应码,200为成功,如果为其他,均表示有问题
int responseCode=httpURLConnection.getResponseCode();
if(responseCode==200)
{
//getInputStream获取服务端返回的数据流。
inputStream=httpURLConnection.getInputStream();
}
} } catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return inputStream;
} }
如果使用POST方法,则需要设置请求参数。下面我们使用POST方式,利用HttpURLConnection完成和上面一样的登录验证功能:
public class LoginTask implements Runnable{ private static String PATH = "http://xxxxx/loginas.aspx";
private static URL url; private String username;
private String password;
public LoginTask(String username, String password) {
// 初始化用户名和密码
this.username = username;
this.password = password;
}
/**
* 通过给定的请求参数和编码格式,获取服务器返回的数据
* @param params 请求参数
* @param encode 编码格式
* @return 获得的字符串
*/
public static String sendPostMessage(Map<String, String> params,
String encode) {
StringBuffer buffer = new StringBuffer();
if (params != null && !params.isEmpty()) {
for (Map.Entry<String, String> entry : params.entrySet()) {
try {
buffer.append(entry.getKey())
.append("=")
.append(URLEncoder.encode(entry.getValue(), encode))
.append("&");//请求的参数之间使用&分割。
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} }
buffer.deleteCharAt(buffer.length() - 1);
System.out.println(buffer.toString());
try {
HttpURLConnection urlConnection = (HttpURLConnection) url
.openConnection();
urlConnection.setConnectTimeout(3000);
//设置允许输入输出
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
byte[] mydata = buffer.toString().getBytes();
//设置请求报文头,设定请求数据类型
urlConnection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
//设置请求数据长度
urlConnection.setRequestProperty("Content-Length",
String.valueOf(mydata.length));
//设置POST方式请求数据
urlConnection.setRequestMethod("POST");
OutputStream outputStream = urlConnection.getOutputStream();
outputStream.write(mydata);
int responseCode = urlConnection.getResponseCode();
if (responseCode == 200) {
return changeInputStream(urlConnection.getInputStream(),
encode);
}
} catch (IOException e) {
e.printStackTrace();
}
}
return "";
} /**
* 把服务端返回的输入流转换成字符串格式
* @param inputStream 服务器返回的输入流
* @param encode 编码格式
* @return 解析后的字符串
*/
private static String changeInputStream(InputStream inputStream,
String encode) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int len = 0;
String result="";
if (inputStream != null) {
try {
while ((len = inputStream.read(data)) != -1) {
outputStream.write(data,0,len);
}
result=new String(outputStream.toByteArray(),encode); } catch (IOException e) {
e.printStackTrace();
}
}
return result;
} @Override
public void run() {
//通过Map设置请求字符串。
try {
url = new URL(PATH);
} catch (Exception e) {
e.printStackTrace();
}
Map<String, String> params = new HashMap<String, String>();
params.put("username", "admin");
params.put("password", "123");
String result=sendPostMessage(params, "utf-8");
System.out.println(result);
} }
总结
那么哪个客户端更好些呢?在2.2之前使用httpClient可以避免一些bug。而在2.3之后的版本中使用HttpURLConnection是最好的选择,简单的API适合于Android开发。透明压缩和应答数据的捕获,减少了网络的使用,提升了性能并且减少了电池的消耗。
在随后我们介绍的开源库中,volley在2.3之前的版本中使用了HttpClient,而在2.3之后使用了HttpURLConnection;android-async-http中封装了HttpClient。
Android网络编程随想录(3)的更多相关文章
- Android网络编程随想录(1)
本系列文章对整个Android网络编程进行了总结,包括基本的TCP/IP协议,HTTP协议,HTTPS协议,HttpClient,UrlConnection,一些网络通信的库到棉花糖新加入的OKHTT ...
- Android网络编程随想录(四)
前面三篇文章从最基础的TCP,HTTP协议理论开始,然后介绍了在Android的开发中所使用的HttpClient和HttpUrlConnection这两种Http客户端.在本文中,我们一起来学习一下 ...
- Android网络编程随想录(2)
上篇文章介绍了传输层TCP协议的理论知识,本文主要介绍了TCP协议基础之上HTTP协议和HTTPS协议的理论知识. HTTP协议基于TCP协议定义了客户端向服务器请求数据的方式,它是面向事务的应用层协 ...
- Android网络编程只局域网传输文件
Android网络编程之局域网传输文件: 首先创建一个socket管理类,该类是传输文件的核心类,主要用来发送文件和接收文件 具体代码如下: package com.jiao.filesend; im ...
- Android网络编程基础
Android网络编程只TCP通信 TCP 服务器端工作的主要步骤如下.步骤1 调用ServerSocket(int port)创建一个ServerSocket,并绑定到指定端口上.步骤2 调用acc ...
- Android网络编程系列 一 TCP/IP协议族
在学习和使用Android网路编程时,我们接触的仅仅是上层协议和接口如Apache的httpclient或者Android自带的httpURlconnection等等.对于这些接口的底层实现我们也有必 ...
- Android网络编程系列 一 Socket抽象层
在<Android网络编程>系列文章中,前面已经将Java的通信底层大致的描述了,在我们了解了TCP/IP通信族架构及其原理,接下来我们就开始来了解基于tcp/ip协议层的Socket抽 ...
- Android 网络编程 Socket
1.服务端开发 创建一个Java程序 public class MyServer { // 定义保存所有的Socket,与客户端建立连接得到一个Socket public static List< ...
- Android网络编程概述
Android网络编程概述 首先,应该了解的几个问题: 1)Android平台网络相关API接口 a) java.net.*(标准Java接口) java.net.*提供与联网有关的类,包括流.数据包 ...
随机推荐
- mysql 统计按天、星期、按月数据的各种 sql 语句 (转录)
文章主要是作为知识整理,内容略有修改,方便以后查阅,内容转摘至 陈宇衡的个人博客,欢迎前去围观. 作为演示效果,先创建一个测试表,在插入两条数据(注:时间为 datetime 类型,unix 时间戳需 ...
- Scala: Types of a higher kind
One of the more powerful features Scala has is the ability to generically abstract across things tha ...
- servlet向浏览器输出信息
package com.aaa.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebS ...
- vue-router同路由地址切换无效解决
本来还想写的,一搜就有现成的,算了: http://blog.csdn.net/peng_guan/article/details/59702699
- SGU495Kids and Prizes 数学期望
题意: 有n个奖品,m个人排队来选礼物,对于每个人,他打开的盒子,可能有礼物,也有可能已经被之前的人取走了,然后把盒子放回原处.为最后m个人取走礼物的期望. 题解: 本道题与之前的一些期望 DP 题目 ...
- Django 模型层(标签、过滤器、模板的继承与导入)
过滤器/自定义过滤器 模板语法中的过滤器类似于python中的内置方法,在我们把数据从后端通过rander传入到前端html文件中之后,在前端我们可以通过模板语法,对传入的数据再进行以通骚操作. 首先 ...
- 【剑指Offer】18、二叉树的镜像
题目描述: 操作给定的二叉树,将其变换为原二叉树的镜像. 解题思路: 求一棵树的镜像的过程:先前序遍历这棵树的每个结点,如果遍历到的结点有子结点,就交换它的两个子结点.当交换完所有的非 ...
- 04-Linux系统编程-第01天(文件IO、阻塞非阻塞)
03-系统函数 系统编程章节大纲 1 文件I/O 2 文件系统 3 进程 4 进程间通信 5 信号 6 进程间关系 7 守护进程 8 线程 9 线程同步 10 网络基础 11 socket编程 12 ...
- 数据挖掘系列 (1) 关联规则挖掘基本概念与 Aprior 算法
转自:http://www.cnblogs.com/fengfenggirl/p/associate_apriori.html 数据挖掘系列 (1) 关联规则挖掘基本概念与 Aprior 算法 我计划 ...
- vue 项目部署到nginx
第一步在控制台终端输入npm run build 打包完成之后项目中会生成一个dist文件夹,直接访问里面的index.html就ok了 第二步配置nginx 第三步重启nginx service n ...