Android系列开发之--HttpPost请求远程XML并DOM解析
先讲一下功能,用户输入用户名、密码后,调用HttpPost像远程计算机发送Http请求,服务器端Hibernate+Struts,容器用的Tomcat7.0,将返回一个XML给Android,其中包含登陆验证信息。
下面根据功能需求,讲一下代码规划,点击界面上的登陆按钮后,将开启一个通信线程,一个外在计步器设为0,当通信失败则计步器累加,计步器达到3时向用户提示网络异常。通信线程内部试用HttpPost将用户信息收集起来传给远方服务器,服务器端的代码涉及J2EE,此处不表,总之就是Hibernate+Struts+dom4j,生成了一个XML,这个XML的格式有如下两种:
1.登陆失败:
[xml]<?xml version="1.0" encoding="UTF-8" ?>
<staff>
<login>0</login>
</staff>[/xml]
2.登陆成功:
[xml]<?xml version="1.0" encoding="UTF-8"?>
<staff>
<login>1</login>
<staff_id>231005651020</staff_id>
<staff_name>丁丁</staff_name>
<dep_id>231005260070</dep_id>
<dep_name>业务支撑中心</dep_name>
<free_number_power>0</free_number_power>
<report_power>1</report_power>
</staff>[/xml]
下面是通信线程的源代码,注释很详细
[java light="false"]
protected class LoginThread extends Thread {
int times = 0;// 为了解决Socket绑定问题,设置重试次数
String username;
String psw;
public LoginThread(int times, String username, String psw) {
this.times = times;
this.username = username;
this.psw = psw;
}
@Override
public void run() {
Looper.prepare(); // 作为需要独立于UI单独执行的线程,这句话是必要条件
if (times == 3) {
UiFactory.alertError(Login.this,R.string.error, R.string.network_error);//外部工程会帮助这个名为Login的Activity弹出错误信息
return;
}// 如果重试次数等于3,则不再重试
User user = null;
HttpPost url = new HttpPost(
"http://xx.xxx.xx.xx:xxxx/TMOPServer/getXMLData.do?action=getStaff");//IP地址我隐藏了,防黑,后面的path是Struts的入口,此处对J2EE服务器端代码不解释
// url两个post值
List nameValuePairs = new ArrayList(2);
nameValuePairs
.add(new BasicNameValuePair("staff_number", username));
nameValuePairs.add(new BasicNameValuePair("password", psw));
try {
// 压入post值
url.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse httpResponse = new DefaultHttpClient().execute(url);// 获取返回
//可以稍微看看这边注释掉的代码,主要是解决返回的xml字符串怎么进入dom解析器的问题,如果httpResponse不用重复使用则可以直接跳过这段注释
// HttpEntity httpEntity=httpResponse.getEntity();
// String xmlSrc =EntityUtils.toString(httpResponse.getEntity());
// Log.d("system", xmlSrc);
// StringReader reader = new StringReader(retSrc);
// InputSource source = new InputSource(reader);
// getContent方法只能用一次,如果第二次调用则IllegalStateException异常
// 报content has been consumed,所以如果要重复调用,或者读取返回的XML字符串时
// 必须使用上面注释的语法,产生一个InputSource流
user=XMLFactory.getUserByXML(httpResponse.getEntity().getContent());//通过DOM解析XML流,并返回一个User对象出来,代码下面贴出来
}catch(SocketException e){
//如果网卡异常,则重试一遍,直至3遍
new LoginThread(times+1, username, psw).start();
e.printStackTrace();
return;
}
catch (Exception e) {
//如果其他异常,则弹出警告窗口
UiFactory.alertError(Login.this,R.string.error, R.string.unknow);
e.printStackTrace();
return;
}
Message message = new Message();
Bundle data = new Bundle();
data.putSerializable("user", user);
message.setData(data);
// 向目标handler发送消息
handler_chk_user.sendMessage(message);//响应线程消息的handler会接受这个User对象,逻辑处理也会在那个handler中,代码在下面
super.run();
Looper.loop();// 作为需要独立于UI单独执行的线程,这句话是必要条件
}
}
[/java]
上面那段代码主要是通信线程,通信线程获取返回值后,将产生一个Message发往handler_chk_user,下面是这个handler的代码:
[java light="false"]
private Handler handler_chk_user = new Handler() {
// hanlder接收到消息时的处理
@Override
public void handleMessage(Message msg) {
Log.d("system", String.valueOf(msg.what));
// 关闭ProgressDialog
progressDialog.dismiss();
User u = (User) msg.getData().get("user");
if (u == null) {
UiFactory.alertError(Login.this,R.string.sorry, R.string.wrong_user);// 验证失败
} else {
checkSuccess(u);
}
}
};
// 验证成功,打开一个新的Activity
protected void checkSuccess(User u) {
Intent i = new Intent();
i.setClass(Login.this, MainTable.class);
i.putExtra("user", u);
Login.this.startActivity(i);
Login.this.finish();
}
[/java]
使用DOM解析XML流,并且构造一个User对象的方法如下在XMLFactory.getUserByXML这个函数中,User类是一个基本的POJO类,或者叫VO类,普通的getter&setter方法即可,此处省略,将DOM解析XML的代码贴出来:
[java light="false" toolbar="true"]
public class XMLFactory {
public static User getUserByXML(InputStream is) throws Exception{
DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbfactory.newDocumentBuilder();
Document document = db.parse(is);//上面是使用DOM解析XML的准备工作,固定的套路
Element root = document.getDocumentElement();//获取根文档
String login="0";//login标志初始化
login = root.getElementsByTagName("login").item(0).getFirstChild().getNodeValue();//获取XML中的login标签值,文章的一开始有XML模板,对应模板跟代码可以看懂
User user=null;
// 如果返回的xml中login标签为1的话,则开始构造User,否则User始终为null
if ("1".equals(login)) {
user = new User(root.getElementsByTagName("staff_id")
.item(0).getFirstChild().getNodeValue());
user.setName(root.getElementsByTagName("staff_name")
.item(0).getFirstChild().getNodeValue());
user.setDep_id(root.getElementsByTagName("dep_id").item(0)
.getFirstChild().getNodeValue());
user.setDep_name(root.getElementsByTagName("dep_name")
.item(0).getFirstChild().getNodeValue());
String fn = root.getElementsByTagName("free_number_power")
.item(0).getFirstChild().getNodeValue();
String re = root.getElementsByTagName("report_power")
.item(0).getFirstChild().getNodeValue();
user.setPow_freeNumber("1".equals(fn));
user.setPow_report("1".equals(re));
}
return user;
}
}
[/java]
至此完成整个HttpPost的发送请求,获取XML响应,DOM解析XML,做出UI反馈的步骤,本例的XML文档非常小,所以用DOM解析表示无鸭梨,如果XML文档很大,或者反馈给Android的XML文档只需要其中的一两个信息时,建议使用SAX解析,不过那样要编写很多消息响应函数,各有利弊。
浙公网安备 33010602011771号