qiaoakai 发表于 2013-1-28 19:06:25

系出名门Android(10)

系出名门Android(10) - HTTP 通信, XML 解析, 通过 Hander 实现异步消息处理


作者:webabcd


介绍
在 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_utilNew -> 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;                  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("下载出错");    }}
页: [1]
查看完整版本: 系出名门Android(10)