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解析,不过那样要编写很多消息响应函数,各有利弊。

posted on 2011-03-20 08:53  newflypig  阅读(398)  评论(0)    收藏  举报

导航