来公司上班这么久,一直做的就是通信这块 - -! 好长时间没写博客了,现在把Android通信这块总结下,我会尽可能详细的讲解所有通信技能。
先列出通信的几种方式:
(1)webservice调用
一、Android通过WebService通信
这也是我们公司Android项目通信的架构,并且封装成一个模块了,具体来说就是:使用HttpURLConnection进行HTTP通信,采用xml数据格式交互。那么问题来了,HttpURLConnection+xml算是WebService通信吗?首先得知道什么是WebService。
WebService是一种跨编程语言和跨操作系统平台的远程调用技术。也就是一个应用程序向外界暴露出一个能通过Web进行调用的API,也就是说能用编程的方法通过Web来调用这个应用程序。XML+XSD,SOAP和WSDL就是构成WebService平台的三大技术。WebService采用http协议传输数据,采用xml封装数据。
XML+XSD:解决了数据的封装和数据类型格式的定义。
SOAP:SOAP协议 = HTTP协议 + XML数据格式。
WebService通过HTTP协议发送请求和接收结果时,发送的请求内容和结果内容都采用XML格式封装,并增加了一些特定的HTTP消息头,以说明HTTP消息的内容格式,这些特定的HTTP消息头和XML内容格式就是SOAP协议。SOAP提供了标准的RPC方法来调用Web Service。
上面说到,WebService采用HTTP协议传输数据,那么在Android如何实现HTTP传输呢,通常用的方式有两种:使用Java标准类库的HttpURLConnection和使用Apache的HttpClient接口。
1、使用HttpURLConnection(官方推荐使用此种方式)
HttpURLConnection的使用很简单,就是使用URL url = new URL("your service ur"),对象来打开一个Hppt连接(HttpURLConnection对象),即new HttpURLConnection() = url.openConnection();.然后使用该对象设置一系列参数,比如请求方法是get还是post,缓存等等。但是为了支持众多请求参数,以及文件传输,做一个比较好的封装是一个问题,如下:
先列出通信的几种方式:
(1)webservice调用
一、Android通过WebService通信
这也是我们公司Android项目通信的架构,并且封装成一个模块了,具体来说就是:使用HttpURLConnection进行HTTP通信,采用xml数据格式交互。那么问题来了,HttpURLConnection+xml算是WebService通信吗?首先得知道什么是WebService。
WebService是一种跨编程语言和跨操作系统平台的远程调用技术。也就是一个应用程序向外界暴露出一个能通过Web进行调用的API,也就是说能用编程的方法通过Web来调用这个应用程序。XML+XSD,SOAP和WSDL就是构成WebService平台的三大技术。WebService采用http协议传输数据,采用xml封装数据。
XML+XSD:解决了数据的封装和数据类型格式的定义。
SOAP:SOAP协议 = HTTP协议 + XML数据格式。
WebService通过HTTP协议发送请求和接收结果时,发送的请求内容和结果内容都采用XML格式封装,并增加了一些特定的HTTP消息头,以说明HTTP消息的内容格式,这些特定的HTTP消息头和XML内容格式就是SOAP协议。SOAP提供了标准的RPC方法来调用Web Service。
上面说到,WebService采用HTTP协议传输数据,那么在Android如何实现HTTP传输呢,通常用的方式有两种:使用Java标准类库的HttpURLConnection和使用Apache的HttpClient接口。
1、使用HttpURLConnection(官方推荐使用此种方式)
HttpURLConnection的使用很简单,就是使用URL url = new URL("your service ur"),对象来打开一个Hppt连接(HttpURLConnection对象),即new HttpURLConnection() = url.openConnection();.然后使用该对象设置一系列参数,比如请求方法是get还是post,缓存等等。但是为了支持众多请求参数,以及文件传输,做一个比较好的封装是一个问题,如下:
* 使用HttpUrlCollection进行Http通信,支持文件传输、post和get提交方式
* @param url 服务地址
* @param paras 参数列表
* @param files 文件列表
* @param authenticated
* @param httpMethod 请求方式
* @return 返回InputStream输入流
* @throws IOException
*/
public InputStream httpRequest(String url,
List<BasicNameValuePair> paras, ArrayList<File> files,
boolean authenticated, String httpMethod) throws IOException {
String end = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
HttpURLConnection con = null;
DataOutputStream ds = null;
InputStream is = null;
int responseCode = -1;
String error = "";
try {
if (httpMethod.equals("GET") && null != paras) {
if (!url.contains("?")){
url += "?";
}
for (BasicNameValuePair kv : paras) {
url += ("&" + kv.key + "=" + kv.value);
}
}
URL uri = new URL(url);
con = (HttpURLConnection) uri.openConnection();
if (this.timeout > 0) {
con.setConnectTimeout(this.timeout);
} else {
con.setConnectTimeout(30000);
}
// con.setReadTimeout(60000);
/* 允许Input、Output,不使用Cache */
con.setDoInput(true);
con.setDoOutput(true);
con.setUseCaches(false);
/* setRequestProperty */
con.setRequestProperty("Connection", "Keep-Alive");
con.setRequestProperty("Charset", "UTF-8");
if (httpMethod.equals("POST")) {
/* 设定传送的method=POST */
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"multipart/form-data;boundary=" + boundary);
/* 设定DataOutputStream */
ds = new DataOutputStream(con.getOutputStream());
/* 添加键值 */
if (null != paras) {
for (BasicNameValuePair kv : paras) {
StringBuilder sb = new StringBuilder();
sb.append(end + twoHyphens + boundary + end);
sb.append("Content-Disposition: form-data; "
+ "name=\"" + kv.key + "\"" + end + end);
sb.append((null==kv.value)?"":kv.value);
// sb.append(twoHyphens + boundary);
byte[] bytes = sb.toString().getBytes("utf8");
ds.write(bytes);
}
ds.write((end + twoHyphens + boundary + end)
.getBytes("utf8"));
}
/* 发送文件 */
if (null != files) {
for (File file : files) {
ds.writeBytes(twoHyphens + boundary + end);
ds.writeBytes("Content-Disposition: form-data; "
+ "name=\"" + file.getName() + "\";filename=\""
+ file.getName() + "\"" + end + end);
FileInputStream fStream = new FileInputStream(file);
String fileName = file.getName();
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int length = -1;
long total = 0;
long fileLength = file.length();
while ((length = fStream.read(buffer)) != -1) {
ds.write(buffer, 0, length);
total += length;
}
ds.write((end + twoHyphens + boundary + end)
.getBytes("utf8"));
fStream.close();
}
/* 所有文件上传完成后加上这一行 */
ds.writeBytes(twoHyphens + boundary + twoHyphens + end);
ds.flush();
}
} else if (httpMethod.equals("GET")) {
//设置为get请求
con.setRequestMethod("GET");
}
responseCode = con.getResponseCode();
/* 取得Response内容 */
is = con.getInputStream();
} catch (MalformedURLException e) {
responseCode = -2;
error = e.getMessage();
e.printStackTrace();
} catch (IOException e) {
responseCode = -3;
error = e.getMessage();
e.printStackTrace();
} catch (Exception e) {
responseCode = -4;
error = e.getMessage();
e.printStackTrace();
} finally {
if (null != ds) {
ds.close();
ds = null;
}
}
return is;
}
通过上面的Http连接就可以进行客户端服务器数据之间的传输,当从服务器请求获取数据时,返回的InputStream流,如果采用xml封装数据,下面以Pull解析为例,将InputStream流解析成ContentValues对象:
/**
* 读取关键词下的节点数据, 以键值对的形式返回
* @param is Xml数据流
* @param key节点名
* @return 键值对
*/
public static ContentValues getAsContentValues(InputStream is, String key ){
try{
is.reset();
}catch(Exception e){
e.printStackTrace();
}
ContentValues ret = null;;
XmlPullParserFactory factory;
try {
factory = XmlPullParserFactory.newInstance();
//生成一个Pull解析器
XmlPullParser parser = factory.newPullParser();
parser.setInput(is, "utf-8");
// 解析器和xml节点值类解析xml
ret = fromXmlContentValues(parser, key);
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if (null == ret){
ret = new ContentValues();
}
return ret;
}
private static ContentValues fromXmlContentValues(XmlPullParser parser, String key) throws XmlPullParserException, IOException{
ContentValues ret = null;
Boolean keyTag = false;//是否进入key节点
Boolean innerTag = false;//是否进入key的子节点
String subKey = ""; //当前key的子节点名称
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
String keyName = parser.getName();
if (eventType == XmlPullParser.END_TAG){
if (keyName.contentEquals(key) && !innerTag){
parser.next();
break;//退出key节点
}else if (keyName.contentEquals(subKey)){
innerTag = false;
}
}
if (eventType == XmlPullParser.START_TAG) {
if (keyName.contentEquals(key) && !keyTag){
keyTag = true;
}else if (keyTag){
//开始读取key的子节点数据
eventType = parser.next();
if (!innerTag){
if (eventType == XmlPullParser.TEXT ||
eventType == XmlPullParser.CDSECT ){
if (null == ret){
ret = new ContentValues();
}
String value = parser.getText();
ret.put(keyName, value);
}
subKey = keyName;
innerTag = true;//进入key的子节点
if (eventType == XmlPullParser.END_TAG){//刚进入就退出的子节点, 说明值为空
if (null == ret){
ret = new ContentValues();
}
String value = "";
ret.put(keyName, value);
innerTag = false;退出key的子节点
}
}
}
}
eventType = parser.next();
}
return ret;
}
2、使用HttpClient通信(在2.2之后官方就不推荐使用这种方式了,使用HttpURLConnection)
HttpClient通信就更简单了,直接上代码
/**
* 根据给定的url地址访问网络,得到响应内容(这里为GET方式访问)
*
* @param url
* 指定天气url地址
*
* @param params 请求参数
* @return 返回结果数据,返回失败时是null
*/
public String getWeatherFromServe(String url,List<String> parameters) {
// 创建一个http请求对象
HttpGet request = new HttpGet(url);
// 创建HttpParams以用来设置HTTP参数
HttpParams params = new BasicHttpParams();
//设置布尔参数,
// params.setBooleanParameter("boolean", false);
//序列化对象参数
// params.setParameter("string", "dsa");
// 设置连接超时或响应超时
HttpConnectionParams.setConnectionTimeout(params, 3000);
HttpConnectionParams.setSoTimeout(params, 5000);
// 创建一个网络访问处理对象
HttpClient httpClient = new DefaultHttpClient(params);
try {
// 执行请求参数项
HttpResponse response = httpClient.execute(request);
// 判断是否请求成功
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
HttpEntity entity = response.getEntity();
// 获得响应信息
String content = EntityUtils.toString(response.getEntity());
return content;
} else {
// 网连接失败,使用Toast显示提示信息
Toast.makeText(mContext, "网络访问失败,请检查手机网络状态!",
Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放网络连接资源
httpClient.getConnectionManager().shutdown();
}
return null;
}
上面的例子中使用的是HttpGet请求方式,也可以使用HttpPost请求。服务器响应的HttpResponse对象获取一个HTTPEntity对象通过getEntity()方法,通过HttpEntity对象就可以获取服务器返回的众多信息。
3、Socket通信
Socket是建立在TCP/IP协议的基础上,就是对TCp/IP的一种封装,Socket提供接口我们使用。关于Socket的文章恐怕一篇两篇也讲不清楚,先放着了,有时间了另开文章详细讲解。