**
前言:
**
恍惚间,从事Android开发已经有半年有余了!之前一直在沉浸于项目中的Bug解决,颇有种一叶障目不见泰山的感觉,对Android网络通信这块儿缺乏一种宏观的认识,适逢一个难得的阴雨周末,躺着也是无聊,倒不如写写耍耍来的痛快!
Android端的开发,除了那些没有植入广告的单机版小游戏小应用,几乎大部分都要牵涉到网络数据的请求。当前Android端的网络编程可以分为两种:一种是通过Socket方式,另外一种则是基于http协议。这两种访问方式大不相同,Socket方式是面向TCP/UDP 协议的,而HTTP通信则是借助于Http协议,这两者分别建立在ISO 七层模型的传输层协议和应用层协议之上。(关于Android中的Socket和http区别,可以查看我的另外一篇文章—–《Android之Http,Socket和Tcp/Ip》)。
Socket通信在Android中应用不多,在桌面程序中倒是应用广泛如众所周知的QQ,关于Socket这篇文章不准备展开,主旨在于总结归纳一下Android 的HTTP通信方式。
一.HTTP通信详细归纳
1.1 http网络连接实现方式可以细分为两类实现:
1.借助于Java核心包 java.net中的HttpURLConnection 类
2.借助于Apache开源组织提供的HttpClient类。
org.apache.http.client.HttpClient;
1.2 HttpURLConnection和HttpClient的区别和联系
HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了,越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源。在 JDK 的 java.net 包中已经提供了访问 HTTP 协议的基本功能:
1.2.1 HttpURLConnection。
HttpURLConnection是java的标准类,HttpURLConnection继承自URLConnection,可用于向指定网站发送GET请求、POST请求。它在URLConnection的基础上提供了如下便捷的方法:
int getResponseCode():获取服务器的响应代码。
String getResponseMessage():获取服务器的响应消息。
String getResponseMethod():获取发送请求的方法。
void setRequestMethod(String method):设置发送请求的方法。
在一般情况下,如果只是需要Web站点的某个简单页面提交请求并获取服务器响应,HttpURLConnection完全可以胜任。但在绝大部分情况下,Web站点的网页可能没这么简单,这些页面并不是通过一个简单的URL就可访问的,可能需要用户登录而且具有相应的权限才可访问该页面。在这种情况下,就需要涉及Session、Cookie的处理了,如果打算使用HttpURLConnection来处理这些细节,当然也是可能实现的,只是处理起来难度就大了。
1.2.2 关于HttpClient
为了更好地处理向Web站点请求,包括处理Session、Cookie等细节问题,Apache开源组织提供了一个HttpClient项目,看它的名称就知道,它是一个简单的HTTP客户端(并不是浏览器),可以用于发送HTTP请求,接收HTTP响应。但不会缓存服务器的响应,不能执行HTML页面中嵌入的Javascript代码;也不会对页面内容进行任何解析、处理。
简单来说,HttpClient就是一个增强版的HttpURLConnection,HttpURLConnection可以做的事情HttpClient全部可以做;HttpURLConnection没有提供的有些功能,HttpClient也提供了,但它只是关注于如何发送请求、接收响应,以及管理HTTP连接。
使用HttpClient发送请求、接收响应很简单,只要如下几步即可。
创建HttpClient对象。
如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。
如果需要发送请求参数,可调用HttpGet、HttpPost共同的setParams(HetpParams params)方法来添加请求参数;对于HttpPost对象而言,也可调用setEntity(HttpEntity entity)方法来设置请求参数。
调用HttpClient对象的execute(HttpUriRequest request)发送请求,执行该方法返回一个HttpResponse。
调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。
另外,Android已经成功地集成了HttpClient,这意味着开发人员可以直接在Android应用中使用Httpclient来访问提交请求、接收响应。
比如一个Android应用需要向指定页面发送请求,但该页面并不是一个简单的页面,只有当用户已经登录,而且登录用户的用户名有效时才可访问该页面。如果使用HttpURLConnection来访问这个被保护的页面,那么需要处理的细节就太复杂了。
其实访问Web应用中被保护的页面,使用浏览器则十分简单,用户通过系统提供的登录页面登录系统,浏览器会负责维护与服务器之间的Sesion,如果用户登录的用户名、密码符合要求,就可以访问被保护资源了。
在Android应用程序中,则可使用HttpClient来登录系统,只要应用程序使用同一个HttpClient发送请求,HttpClient会自动维护与服务器之间的Session状态,也就是说程序第一次使用HttpClient登录系统后,接下来使用HttpClient即可访问被保护页了。
详情可点击链接:
http://blog.csdn.net/wszxl492719760/article/details/8522714
**
二.在代码中的实际使用
**
2.1 HttpClient使用
使用背景:Android 客户端访问Java后台,获取后台数据,数据请求和下载都采用UTF-8编码。
/**
* 请求服务器的方法
* @param Url
* @param jso
* @return
*/
public String NetWork(String servletName,List<String> Name,List<String> Value){
//创建默认的 HttpClient 实例
HttpClient httpClient = new DefaultHttpClient();
// 采用http "Post"访问Java后台
HttpPost httpPost = new HttpPost(url+servletName);
//post方式需要传入的参数
HttpParams hp = httpPost.getParams();
hp.setIntParameter(HttpConnectionParams.SO_TIMEOUT, 30000); // 超时设置
hp.setIntParameter(HttpConnectionParams.CONNECTION_TIMEOUT, 30000);// 连接超时
try {
if(Name!=null){
// 来自org.apache.http包。用于保存键值对name-value
List<NameValuePair> formParams = new ArrayList<NameValuePair>();
for (int i = 0; i < Name.size(); i++) {
formParams.add(new BasicNameValuePair(Name.get(i), Value.get(i)));
}
//网络访问传入的参数统一采用UTF-8编码
UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(formParams, "UTF-8");
httpPost.setEntity(urlEncodedFormEntity);
}
// java后台返回的response对象
HttpResponse httpResponse = null;
httpResponse = httpClient.execute(httpPost);
//respons对象携带的内容
HttpEntity httpEntity = httpResponse.getEntity();
if (httpEntity != null)
{
//java 后台返回内容采用UTF-8编码
String content = handleEntity(httpEntity, "UTF-8");
return content;
}
else
{
return null;
}
} catch (Exception e)
{
e.printStackTrace();
return null;
}finally {
//关闭连接,释放资源
httpClient.getConnectionManager().shutdown();
}
}
2.1.1 关于handleEntity
网络数据的处理说到底也是对java字节流的处理,handleEntity就是对java后台返回的字节流进行处理后封装为字符对象。
代码如下:
public String handleEntity(HttpEntity entity, String charset)
throws IOException {
if (entity == null)
return null;
//网络数据使用字节流对象存储
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
//字节buffer
byte[] buffer = new byte[1024];
@SuppressWarnings("unused")
int len = -1;
//获取输入字节流对象
InputStream is = entity.getContent();
while ((len = is.read(buffer)) != -1)
{
//将buffer数据写入字节流对象outStream
outStream.write(buffer, 0, len);
}
byte[] data = outStream.toByteArray();
outStream.close();
is.close();
// 生成指定编码格式的字符
return new String(data, charset);
}
2.2 HttpURLConnection 使用
2.2.1 获取输入流
// //由于得到一个InputStream对象
public InputStream getInputStream(String urlStr) throws IOException
{
InputStream is = null;
try
{
url = new URL(urlStr);
HttpURLConnection urlConn = (HttpURLConnection)url.openConnection();
urlConn.setRequestMethod("GET");
urlConn.setDoInput(true);
urlConn.setDoOutput(true);
urlConn.setUseCaches(false);
urlConn.setConnectTimeout(5000);
urlConn.setReadTimeout(5000);
////实现连接
urlConn.connect();
if (urlConn.getResponseCode() == 200)
{
is = urlConn.getInputStream() ;
//}
}
catch(MalformedURLException e)
{
e.printStackTrace();
}
return is;
}
2.2.2 获取InputStream后转化为Bitmap
图片操作
//网络图片获取
//urlpath = "http://*****/splashy_above.png"
public static Bitmap getImage(String urlpath)
throws Exception
{
URL url = new URL(urlpath);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5*1000);
conn.setRequestMethod("GET");
Bitmap bitmap = null;
if(conn.getResponseCode() == 200)
{
InputStream inputStream = conn.getInputStream();
bitmap = BitmapFactory.decodeStream(inputStream);
}
return bitmap;
}
2.2.3 将 Input对象写入文件
文件操作。
*将一个InputStream里面的数据写入到SD卡中
* */
public File write2SDFromInput(String path,String fileName,InputStream input)
{
File file = null;
OutputStream output = null;
try
{
//将一个InputStream 对象的数据写入到 BufferedOutputStream bos对象中
byte[] arr = new byte[1];
//缓冲流和字节流对象对接
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(baos);
//循环操作将输入流inputStream对象中的字节流写入到字节缓存输出流中
int n = input.read(arr);
while (n > 0)
{
bos.write(arr);
n = input.read(arr);
}
bos.close();
//该函数只是在SD卡上创建文件夹
createSDDir(path);
//在上面创建好文件夹下创建文件
file = createSDFile(path + fileName);
output = new FileOutputStream(file);
output.write(baos.toByteArray());
output.flush();
baos.close();
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
try
{
output.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
return file;
}
**
三.总结
**
网上查阅一番资料后再对照下自己的代码,恍然间好困!看代码真的好累啊…呵呵,其实网络操作说白了就是java的网络核心篇加上java的字节流操作,其中需要注意的地方先列出来以备后用:
1.HTTP协议之post和get的区别。
2.在Android 4.0之后,不允许在主线程中进行网络连接,必须采用线程机制。
3.建议采用线程 –Hander –Message 的Android消息机制进行网络数据操作。
Thread t.start();
t.run()里面进行网络访问。
t.run()之后访问完成后发送Message。
Handler 截获message后将接收到的数据在View中予以展示。
好了,越扯越多了,说到Android的消息机制我现在还是有点昏,就先总结到这里吧!