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

[索引页]
[源码下载]


系出名门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_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(
"https://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(
"下载出错");
    }
}


OK
[源码下载]
posted @ 2010-01-29 08:20  webabcd  阅读(7287)  评论(7编辑  收藏  举报