天天看點

系出名門Android(10) - HTTP 通信, XML 解析, 通過 Hander 實作異步消息處理

<a href="http://webabcd.blog.51cto.com/1787395/341976" target="_blank">[索引頁]</a>

<a href="http://down.51cto.com/data/100088" target="_blank">[源碼下載下傳]</a>

系出名門Android(10) - HTTP 通信, XML 解析, 通過 Hander 實作異步消息處理

介紹

在 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 文檔的回調函數 

        public void endDocument() throws SAXException { 

                super.endDocument(); 

        // 一發現元素開始标記就回調此函數 

        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");         

        // 一發現元素結束标記就回調此函數 

        public void endElement(String uri, String localName, String qName) 

                        throws SAXException { 

                        mIsTitleTag = false; 

                        mIsSalaryTag = false; 

                        mIsBirthTag = false; 

        // 一發現元素值或屬性值就回調此函數 

        public void characters(char[] ch, int start, int length) 

                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

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. */ 

        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() { 

                                httpPostDemo(); 

                Button btn3 = (Button) this.findViewById(R.id.btn3); 

                // DOM - Document Object Model 

                btn3.setText("DOM 解析 XML"); 

                btn3.setOnClickListener(new Button.OnClickListener() { 

                                DOMDemo(); 

                Button btn4 = (Button) this.findViewById(R.id.btn4); 

                // SAX - Simple API for XML 

                btn4.setText("SAX 解析 XML"); 

                btn4.setOnClickListener(new Button.OnClickListener() { 

                                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(){ 

                        String url = "http://5billion.com.cn/post.php"; 

                        Map&lt;String, String&gt; data = new HashMap&lt;String, String&gt;(); 

                        data.put("name", "webabcd"); 

                        data.put("salary", "100"); 

                        DefaultHttpClient httpClient = new DefaultHttpClient(); 

                        HttpPost httpPost = new HttpPost(url); 

                        ArrayList&lt;BasicNameValuePair&gt; postData = new ArrayList&lt;BasicNameValuePair&gt;(); 

                        for (Map.Entry&lt;String, String&gt; 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"; 

                        HttpEntity httpEntity = response.getEntity(); 

                        InputStream is = httpEntity.getContent(); 

                        result += convertStreamToString(is); 

                        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&lt;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); 

        // 以 SAX 方式解析 XML(xml 資料詳見 res/raw/employee.xml) 

        // SAX 解析器的實作詳見 MySAXHandler.java 

        private void SAXDemo(){ 

                        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); 

        // 輔助方法,用于把流轉換為字元串 

        private String convertStreamToString(InputStream is) { 

                BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 

                StringBuilder sb = new StringBuilder();        

                String line = null; 

                        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 -&gt; Java Project

項目上點右鍵 -&gt; Build Path -&gt; Add Libraries -&gt; User Library -&gt; User Libraries -&gt; New -&gt; 為類庫起個名字 -&gt; 選中這個類庫 -&gt; Add JARs 導入 Android 的 jar 包

項目上點右鍵 -&gt; Build Path -&gt; Add Libraries -&gt; User Library -&gt; 選擇 Android 庫

DownloadManagerAsync.java

package webabcd.util; 

import java.io.File; 

import java.io.FileOutputStream; 

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 &lt; fileSize &amp;&amp; readNum != -1) { 

                                                readNum = inputStream.read(buffer); 

                                                if (readNum &gt; -1) { 

                                                        outputStream.write(buffer); 

                                                        readCount = readCount + readNum; 

                                                        int percent = (int) (readCount * 100 / fileSize); 

                                                        if (percent &gt; 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) { 

                                        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()); 

        // 向 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); 

        private void sendMessage(int what, int arg1, int arg2) { 

                Message msg = mHandler.obtainMessage(what, arg1, arg2); 

        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); 

                        case FILE_DOWNLOAD_COMPLETE: 

                                if (mOnDownloadCompleteListener != null) 

                                        mOnDownloadCompleteListener.onDownloadComplete(mManager, 

                                                        msg.obj); 

                        case FILE_DOWNLOAD_ERROR: 

                                if (mOnDownloadErrorListener != null) 

                                        mOnDownloadErrorListener.onDownloadError(mManager, 

                                                        (Exception) msg.obj); 

                        default: 

        // 定義連接配接事件 

        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 類庫

項目上點右鍵 -&gt; Properties -&gt; Java Build Path -&gt; Projects -&gt; Add 引用上面的類庫

package com.webabcd.handler; 

import webabcd.util.DownloadManagerAsync; 

public class Main extends Activity implements 

                DownloadManagerAsync.OnDownloadCompleteListener, 

                DownloadManagerAsync.OnDownloadUpdateListener, 

                DownloadManagerAsync.OnDownloadErrorListener { 

        TextView txt; 

                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("下載下傳出錯"); 

OK

     本文轉自webabcd 51CTO部落格,原文連結:http://blog.51cto.com/webabcd/342102,如需轉載請自行聯系原作者

繼續閱讀