介绍
在 Android 中与服务端做 HTTP 通信,解析 XML,通过 Handler 实现异步消息处理
HTTP 通信 - 与服务端做 HTTP 通信,分别以 GET 方式和 POST 方式做演示
XML 解析 - 可以用两种方式解析 XML,分别是 DOM 方式和 SAX 方式
异步消息处理 - 通过 Handler 实现异步消息处理,以一个自定义的异步下载类来说明 Handler 的用法
1、HTTP 通信和 XML 解析的 Demo
MySAXHandler.java
package com.webabcd.communication; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; // 继承 DefaultHandler 以实现指定 XML 的 SAX 解析器 // DOM - W3C 标准,需要把 xml 数据全部加载完成后才能对其做解析,可对树做任意遍历 // SAX - 流式解析,通过事件模型解析 xml,只能顺序解析 public class MySAXHandler extends DefaultHandler { private boolean mIsTitleTag=false; private boolean mIsSalaryTag=false; private boolean mIsBirthTag=false; private String mResult=""; // 打开 xml 文档的回调函数 @Override public void startDocument() throws SAXException { // TODO Auto-generated method stub super.startDocument(); } // 关闭 xml 文档的回调函数 @Override public void endDocument() throws SAXException { // TODO Auto-generated method stub super.endDocument(); } // 一发现元素开始标记就回调此函数 @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (localName == "title") mIsTitleTag=true; else if (localName == "salary") mIsSalaryTag=true; else if (localName == "dateOfBirth") mIsBirthTag=true; else if (localName == "employee") mResult += "/nname:" + attributes.getValue("name"); } // 一发现元素结束标记就回调此函数 @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (localName == "title") mIsTitleTag=false; else if (localName == "salary") mIsSalaryTag=false; else if (localName == "dateOfBirth") mIsBirthTag=false; } // 一发现元素值或属性值就回调此函数 @Override public void characters(char[] ch, int start, int length) throws SAXException { if (mIsTitleTag) mResult += new String(ch, start, length); else if (mIsSalaryTag) mResult += " salary:" + new String(ch, start, length); else if (mIsBirthTag) mResult += " dateOfBirth:" + new String(ch, start, length); } public String getResult(){ return mResult; } }
Main.java
package com.webabcd.communication; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.protocol.HTTP; import org.apache.http.util.ByteArrayBuffer; import org.apache.http.util.EncodingUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; public class Main extends Activity { private TextView textView; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); textView=(TextView) this.findViewById(R.id.textView); Button btn1=(Button) this.findViewById(R.id.btn1); btn1.setText("http get demo"); btn1.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { httpGetDemo(); } }); Button btn2=(Button) this.findViewById(R.id.btn2); btn2.setText("http post demo"); btn2.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { httpPostDemo(); } }); Button btn3=(Button) this.findViewById(R.id.btn3); // DOM - Document Object Model btn3.setText("DOM 解析 XML"); btn3.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { DOMDemo(); } }); Button btn4=(Button) this.findViewById(R.id.btn4); // SAX - Simple API for XML btn4.setText("SAX 解析 XML"); btn4.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { SAXDemo(); } }); } // Android 调用 http 协议的 get 方法 // 本例:以 http 协议的 get 方法获取远程页面响应的内容 private void httpGetDemo(){ try { // 模拟器测试时,请使用外网地址 URL url=new URL("http://xxx.xxx.xxx"); URLConnection con=url.openConnection(); String result="http status code: " + ((HttpURLConnection)con).getResponseCode() + "/n"; // HttpURLConnection.HTTP_OK InputStream is=con.getInputStream(); BufferedInputStream bis=new BufferedInputStream(is); ByteArrayBuffer bab=new ByteArrayBuffer(32); int current=0; while ( (current=bis.read()) != -1 ){ bab.append((byte)current); } result += EncodingUtils.getString(bab.toByteArray(), HTTP.UTF_8); bis.close(); is.close(); textView.setText(result); } catch (Exception e) { textView.setText(e.toString()); } } // Android 调用 http 协议的 post 方法 // 本例:以 http 协议的 post 方法向远程页面传递参数,并获取其响应的内容 private void httpPostDemo(){ try { // 模拟器测试时,请使用外网地址 String url="http://5billion.com.cn/post.php"; Map<String, String> data=new HashMap<String, String>(); data.put("name", "webabcd"); data.put("salary", "100"); DefaultHttpClient httpClient=new DefaultHttpClient(); HttpPost httpPost=new HttpPost(url); ArrayList<BasicNameValuePair> postData=new ArrayList<BasicNameValuePair>(); for (Map.Entry<String, String> m : data.entrySet()) { postData.add(new BasicNameValuePair(m.getKey(), m.getValue())); } UrlEncodedFormEntity entity=new UrlEncodedFormEntity(postData, HTTP.UTF_8); httpPost.setEntity(entity); HttpResponse response=httpClient.execute(httpPost); String result="http status code: " + response.getStatusLine().getStatusCode() + "/n"; // HttpURLConnection.HTTP_OK HttpEntity httpEntity=response.getEntity(); InputStream is=httpEntity.getContent(); result += convertStreamToString(is); textView.setText(result); } catch (Exception e) { textView.setText(e.toString()); } } // 以 DOM 方式解析 XML(xml 数据详见 res/raw/employee.xml) private void DOMDemo(){ try { DocumentBuilderFactory docFactory=DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder=docFactory.newDocumentBuilder(); Document doc=docBuilder.parse(this.getResources().openRawResource(R.raw.employee)); Element rootElement=doc.getDocumentElement(); NodeList employeeNodeList=rootElement.getElementsByTagName("employee"); textView.setText("DOMDemo" + "/n"); String title=rootElement.getElementsByTagName("title").item(0).getFirstChild().getNodeValue(); textView.append(title); for (int i=0; i<employeeNodeList.getLength(); i++){ Element employeeElement=((Element)employeeNodeList.item(i)); String name=employeeElement.getAttribute("name"); String salary=employeeElement.getElementsByTagName("salary").item(0).getFirstChild().getNodeValue(); String dateOfBirth=employeeElement.getElementsByTagName("dateOfBirth").item(0).getFirstChild().getNodeValue(); textView.append("/nname: "+name+" salary: "+salary+" dateOfBirth: " + dateOfBirth); } } catch (Exception e) { textView.setText(e.toString()); } } // 以 SAX 方式解析 XML(xml 数据详见 res/raw/employee.xml) // SAX 解析器的实现详见 MySAXHandler.java private void SAXDemo(){ try { SAXParserFactory saxFactory=SAXParserFactory.newInstance(); SAXParser parser=saxFactory.newSAXParser(); XMLReader reader=parser.getXMLReader(); MySAXHandler handler=new MySAXHandler(); reader.setContentHandler(handler); reader.parse(new InputSource(this.getResources().openRawResource(R.raw.employee))); String result=handler.getResult(); textView.setText("SAXDemo" + "/n"); textView.append(result); } catch (Exception e) { textView.setText(e.toString()); } } // 辅助方法,用于把流转换为字符串 private String convertStreamToString(InputStream is) { BufferedReader reader=new BufferedReader(new InputStreamReader(is)); StringBuilder sb=new StringBuilder(); String line=null; try { while ((line=reader.readLine()) != null) { sb.append(line + "/n"); } } catch (IOException e) { e.printStackTrace(); } finally { try { is.close(); } catch (IOException e) { e.printStackTrace(); } return sb.toString(); } }
2、用 Handler 来实现异步消息处理,以一个可以实时汇报下载进度的异步下载类为例
开发一个 Android 类库,本例中此类库名为 webabcd_util
New -> Java Project
项目上点右键 -> Build Path -> Add Libraries -> User Library -> User Libraries -> New -> 为类库起个名字 -> 选中这个类库 -> Add JARs 导入 Android 的 jar 包
项目上点右键 -> Build Path -> Add Libraries -> User Library -> 选择 Android 库
DownloadManagerAsync.java
package webabcd.util; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; import org.apache.http.protocol.HTTP; import android.os.Handler; import android.os.Message; import android.util.Log; // 以一个实例,即异步下载,来演示 Android 的异步消息处理(用 Handler 的方式) public class DownloadManagerAsync { public DownloadManagerAsync() { } // 实例化自定义的 Handler EventHandler mHandler=new EventHandler(this); // 按指定 url 地址下载文件到指定路径 public void download(final String url, final String savePath) { new Thread(new Runnable() { public void run() { try { sendMessage(FILE_DOWNLOAD_CONNECT); URL sourceUrl=new URL(url); URLConnection conn=sourceUrl.openConnection(); InputStream inputStream=conn.getInputStream(); int fileSize=conn.getContentLength(); File savefile=new File(savePath); if (savefile.exists()) { savefile.delete(); } savefile.createNewFile(); FileOutputStream outputStream=new FileOutputStream( savePath, true); byte[] buffer=new byte[1024]; int readCount=0; int readNum=0; int prevPercent=0; while (readCount < fileSize && readNum != -1) { readNum=inputStream.read(buffer); if (readNum > -1) { outputStream.write(buffer); readCount=readCount + readNum; int percent=(int) (readCount * 100 / fileSize); if (percent > prevPercent) { // 发送下载进度信息 sendMessage(FILE_DOWNLOAD_UPDATE, percent, readCount); prevPercent=percent; } } } outputStream.close(); sendMessage(FILE_DOWNLOAD_COMPLETE, savePath); } catch (Exception e) { sendMessage(FILE_DOWNLOAD_ERROR, e); Log.e("MyError", e.toString()); } } }).start(); } // 读取指定 url 地址的响应内容 public void download(final String url) { new Thread(new Runnable() { public void run() { try { sendMessage(FILE_DOWNLOAD_CONNECT); URL sourceUrl=new URL(url); URLConnection conn=sourceUrl.openConnection(); conn.setConnectTimeout(3000); BufferedReader reader=new BufferedReader( new InputStreamReader(conn.getInputStream(), HTTP.UTF_8)); String line=null; StringBuffer content=new StringBuffer(); while ((line=reader.readLine()) != null) { content.append(line); } reader.close(); sendMessage(FILE_DOWNLOAD_COMPLETE, content.toString()); } catch (Exception e) { sendMessage(FILE_DOWNLOAD_ERROR, e); Log.e("MyError", e.toString()); } } }).start(); } // 向 Handler 发送消息 private void sendMessage(int what, Object obj) { // 构造需要向 Handler 发送的消息 Message msg=mHandler.obtainMessage(what, obj); // 发送消息 mHandler.sendMessage(msg); } private void sendMessage(int what) { Message msg=mHandler.obtainMessage(what); mHandler.sendMessage(msg); } private void sendMessage(int what, int arg1, int arg2) { Message msg=mHandler.obtainMessage(what, arg1, arg2); mHandler.sendMessage(msg); } private static final int FILE_DOWNLOAD_CONNECT=0; private static final int FILE_DOWNLOAD_UPDATE=1; private static final int FILE_DOWNLOAD_COMPLETE=2; private static final int FILE_DOWNLOAD_ERROR=-1; // 自定义的 Handler private class EventHandler extends Handler { private DownloadManagerAsync mManager; public EventHandler(DownloadManagerAsync manager) { mManager=manager; } // 处理接收到的消息 @Override public void handleMessage(Message msg) { switch (msg.what) { case FILE_DOWNLOAD_CONNECT: if (mOnDownloadConnectListener != null) mOnDownloadConnectListener.onDownloadConnect(mManager); break; case FILE_DOWNLOAD_UPDATE: if (mOnDownloadUpdateListener != null) mOnDownloadUpdateListener.onDownloadUpdate(mManager, msg.arg1); break; case FILE_DOWNLOAD_COMPLETE: if (mOnDownloadCompleteListener != null) mOnDownloadCompleteListener.onDownloadComplete(mManager, msg.obj); break; case FILE_DOWNLOAD_ERROR: if (mOnDownloadErrorListener != null) mOnDownloadErrorListener.onDownloadError(mManager, (Exception) msg.obj); break; default: break; } } } // 定义连接事件 private OnDownloadConnectListener mOnDownloadConnectListener; public interface OnDownloadConnectListener { void onDownloadConnect(DownloadManagerAsync manager); } public void setOnDownloadConnectListener(OnDownloadConnectListener listener) { mOnDownloadConnectListener=listener; } // 定义下载进度更新事件 private OnDownloadUpdateListener mOnDownloadUpdateListener; public interface OnDownloadUpdateListener { void onDownloadUpdate(DownloadManagerAsync manager, int percent); } public void setOnDownloadUpdateListener(OnDownloadUpdateListener listener) { mOnDownloadUpdateListener=listener; } // 定义下载完成事件 private OnDownloadCompleteListener mOnDownloadCompleteListener; public interface OnDownloadCompleteListener { void onDownloadComplete(DownloadManagerAsync manager, Object result); } public void setOnDownloadCompleteListener( OnDownloadCompleteListener listener) { mOnDownloadCompleteListener=listener; } // 定义下载异常事件 private OnDownloadErrorListener mOnDownloadErrorListener; public interface OnDownloadErrorListener { void onDownloadError(DownloadManagerAsync manager, Exception e); } public void setOnDownloadErrorListener(OnDownloadErrorListener listener) { mOnDownloadErrorListener=listener; } }
调用上面的自定义的 Android 类库
项目上点右键 -> Properties -> Java Build Path -> Projects -> Add 引用上面的类库
Main.java
package com.webabcd.handler; import android.app.Activity; import android.os.Bundle; import android.widget.TextView; import webabcd.util.DownloadManagerAsync; public class Main extends Activity implements DownloadManagerAsync.OnDownloadCompleteListener, DownloadManagerAsync.OnDownloadUpdateListener, DownloadManagerAsync.OnDownloadErrorListener { TextView txt; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); DownloadManagerAsync manager=new DownloadManagerAsync(); manager.setOnDownloadCompleteListener(this); manager.setOnDownloadUpdateListener(this); manager.download("http://files.cnblogs.com/webabcd/Android.rar", "/sdcard/Android.rar"); txt=(TextView) this.findViewById(R.id.txt); txt.setText("开始下载"); } public void onDownloadComplete(DownloadManagerAsync manager, Object result) { txt.setText("下载完成"); } public void onDownloadUpdate(DownloadManagerAsync manager, int percent) { txt.setText("下载进度:" + String.valueOf(percent) + "%"); } public void onDownloadError(DownloadManagerAsync manager, Exception e) { txt.setText("下载出错"); } }