Android开发&Http协议及数据解析

1.通过http发送或读取数据(Post,Get)

HttpClient方式已被废弃。
1.1 从指定url获取返回信息(GET/POST)

private void requestHttpView(final String urlRequest){
    new Thread(new Runnable() {
        @Override
        public void run() {
            HttpURLConnection connection=null;
            try {
                URL url=new URL(urlRequest);
                connection=(HttpURLConnection)url.openConnection();
                //从指定url建立链接。
                connection.setRequestMethod("GET");
                //设置连接方式。

/*
connection.setRequestMethod("POST");
//需要发送数据时,将链接方式设置为“POST”
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
//获取连接的输出流(输出流输出流是相对本机而言的)
out.writeBytes("username=admin&password=123456");
//将需要发送的数据送入输出流
*/

                connection.setConnectTimeout(5000);
                //设置连接超时。
                connection.setReadTimeout(5000);
                //设置读取超时。
                InputStream inputStream=connection.getInputStream();
                //获取链接的输入流。
                BufferedReader reader=new BufferedReader(new InputStreamReader(inputStream));
                //新建BufferedReader对象,读取数据方便
                StringBuilder builder=new StringBuilder();
                String line;
                while((line=reader.readline())!=null){
                    builder.append(line);
                }//输入流读取完毕。
                Message message=new Message();
                message.what=REQUEST_OK;
                message.obj=builder;
                handler.sendMessage(message);
                //将获取到的数据交给主线程处理。
            } catch (IOException e) {
                Message message=new Message();
                message.what=REQUEST_ERROR;
                handler.sendMessage(message);
            } finally {
                if (connection!=null) {
                    connection.disconnect();
                    //关闭链接
                }
            }
        }
    }).start();
}

1.2 被废弃的HttpClient方式:

private void POSTUrl(String url){
    new Thread(new Runnable() {
        @Override

        public void run() {
            Message message=null;
            try {
                HttpClient client=new DefaultHttpClient();
                //新建“客户”对象
                HttpPost httpPost=new HttpPost(url);
                //新建post请求
                List<NameValuePair> pairs=new ArrayList<NameValuePair>();
                pairs.add(new BasicNameValuePair("title", "hello"));
                UrlEncodedFormEntity entity=new UrlEncodedFormEntity(pairs,"utf-8");
                httpPost.setEntity(entity);
                //将要发送内容添加到list中,并提交给post对象;
                HttpResponse response=client.execute(httpPost);
                if(response.getStatusLine().getStatusCode()==200){
                //返回值状态为200代表成功
                    message.what=REQUEST_OK;
                    HttpEntity httpEntity=response.getEntity();
                    message.obj= EntityUtils.toString(httpEntity,"utf-8");
                    //取出访问url返回的内容。
                }else{
                    message.what=REQUEST_ERROR;
                    message.obj="statusCode not equals 200";
                }
            } catch (IOException e) {
                message.what=REQUEST_ERROR;
                message.obj=e.toString();
            }finally {
                handler.sendMessage(message);
                //交给主线程处理
            }
        }
    }).start();
}
//此时方法只供参考,说明http请求的另一种模式。

2. 数据解析——xml文档;

访问某个url返回的数据,大都是html语言,例如WebView控件就是将http请求以及获取的数据封装,用浏览器的方式进行查看。
还有些返回的内容只提供数据,不能形成可视化网页,例如xml和json。这些内容大都不要进行解析,从中提取想要的information。
2.1 解析xml文档——pull
Pull解析器提供的事件类型总共有5种,分别如下:

  • (1)START_DOCUMENT 文档开始
  • (2)START_TAG     开始节点
  • (3)TEXT        文本节点
  • (4)END_TAG     节点结束
  • (5)END_DOCUMENT 文档结束

pull解析原理:从文档头开始,整个文档由节点组成,有些节点中包含属性和文本;

<qq mm="a" nn="b">text</qq>
//<qq ……>表示qq节点的开始
//<qq mm="a" nn="b">text</qq>就是节点。
//qq是节点名字
//mm和nn都是属性名
//a和b是节点对应的值
//text是文本
//遇到</qq>代表节点qq结束

pull方式解析,就是新建一个xmlPullParser对象,然后从头开始“推”,开始解析时,将事件设置为START_DOCUMENT,当碰到节点开始标志时,会将事件设置为START_TAG,如此解析下去,直到文档结束,然后将事件为END_DOCUMENT 文档结束;下面介绍解析时用到的方法:

(1)int getAttributeCount(); //获取当前节点的属性个数
(2)String getAttributeValue(int index); //获取属性值,参数表示第index个属性。
(3)int getEventType();//获取事件类型
(4)String getName();//用于START_TAG和END_TAG事件中,获取当前节点的名字
(5)int next();//处理下一个节点
(6)String nextText();//用于START_TAG事件中,获得下一个TEXT类型的节点(就是文本)

pull解析代码

private String[] analyzeXML(String xml,String[] names){
    String[] values=new String[names.length];
    try {
        XmlPullParserFactory factory=XmlPullParserFactory.newInstance();
        XmlPullParser parser=factory.newPullParser();
        //利用“工厂”生产一个进行pull解析的对象。
        parser.setInput(new StringReader(xml));
        //设置进行pull解析的内容或输入流
        int type=parser.getEventType();
        //获取当前的事件类型。
        while(type!=XmlPullParser.END_DOCUMENT){
        //不断的读取下一个节点,直到文档结束。
            String nodeName=parser.getName();
            switch (type){
                case XmlPullParser.START_TAG:{
                    for(int i=0;i<names.length;i++){
                        if(names[i].equals(nodeName)){
                            values[i]=parser.nextText();
                            //nodeName为当前节点名
                            break;
                        }
                    }
                    break;
                }
                case XmlPullParser.END_TAG:{
                    break;
                }
                default:{
                    break;
                }
            }
            type=parser.next();
        }
    } catch (Exception e) {
    }
    return values;
    //返回获取到的对应节点的文本
}

2.2 解析xml文档——sax
sax解析原理:sax解析方式与pull有些类似,都是一边读取一边解析,不过sax将解析以类的形式封装起来,只需要重写方法就可以了。
sax属于事件驱动,每当遇到一定的标志就执行特定的方法;pull像是”手动“驱动,需要代码显示控制读取,判断,取值,再读取……
sax解析代码:

SAXParserFactory factory=SAXParserFactory.newInstance();
XMLReader xmlReader=factory.newSAXParser().getXMLReader();
MyHandler handler = new MyHandler();
xmlReader.setContentHandler(handler);
// 将ContentHandler的实例设置到XMLReader
//(setContentHandler方法需要接收一个处理解析事件的类参数)
xmlReader.parse(new InputSource(new StringReader(xmlData)));
// 开始执行解析

myHandler类一般继承DefaultHandler类,然后重写其中的事件方法。
MyHandler代码:

public class MyHandler extends DefaultHandler {
    @Override
    public void startDocument() throws SAXException {
        //开始解析文档时调用,进行初始化的工作。
    }
    @Override
    public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {
        //开始某节点时候调用
        /*uri - 名称空间 URI,如果节点没有任何名称空间 URI,或者没有正在执行名称空间处理,则为空字符串。
         *localName - 本地名称(不带前缀),如果没有正在执行名称空间处理,则为空字符串。
         *qName - 限定的名称(带有前缀),如果限定的名称不可用,则为空字符串。(节点名,一般读取数据时比较qName是否是自己想要的内容名称,然后提取数据)
         *attributes - 附加到节点的属性。如果没有属性,则它将是空的 Attributes 对象。
         */
    }
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        //获取文本时候调用,准确的说应该是在读取某节点中内容时候调用。
        /*ch - 字符。
         *length - 从字符数组中使用的字符数。
         *start - 字符数组中的开始位置
         */     
    }
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        //节点结束时调用
        //与startElement参数基本相同
    }
    @Override
    public void endDocument() throws SAXException {
        //文档结束时调用
    }
}
//从解析方法中也可以看出,xml格式非常重要,不规范的书写方式会导致解析失败。

这样看起来是不是发现sax除了比较”自动化“之外,跟pull解析没有多大的区别。

2.3 解析xml文档——DOM
js中,dom指的是文档对象模型,也是操作页面最基本最常用的方法。

DOM原理: pull与sax解析都是无”记忆”的,即对整个文档而言,只能在触发事件时进行内容的读取,不可能依靠前两种解析方式理清文档结构。DOM则是先将文档 ”通读“,以节点建立”树“的模型,在想要获取内容时只要知道在”树“中的位置,就可以随时读取,不过因为要建立模型,因此会占用较大的内存空间。

DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(file); 
//其实解析xml文档方法步骤都差不多,先构建出解析器,再传入需要解析的内容,然后对内容进行分析。

此时获得的doc包含整个文档中的节点。直观来看:
来自互联网

(随便找了个xml的dom树)

//可以看到,dom“树”的节点是由节点(非TEXT类型)和文本组成的(文本总是没有子节点的子节点,属性相当于节点的“附加"信息。我们获取的内容就是指文本)

//系统不可能将”树“形象的映射到内存里,因此dom解析是通过栈来实现的,因为xml文档的规范性,通过查看栈的数据,就可以”立体化“dom树。

//需要注意的是,dom解析类似于引用,如果改变生成的doc,那么实际的文档将会被改变。

//dom查找数据可以通过根节点不停的查找子节点,直至定位到想要的节点,然后获取内容。

节点——Node:节点本来是数据结构中tree的组成部分,不过在xml文档中,所有的内容都可以称为节点。在Dom中,节点分为十二总,涵盖了文档中所有部分,我们上面说的”文本“,其实只是TEXTNODE类型的节点,不过为了直观,把两者区分开来。
元素——Element:元素和节点很相似,事实上,看源码的话可以发现Element继承自Node,Element相当于Node的扩展,不过使用起来较为方便一些。
Node与Element的区别

例:

private String xmlAnalize(String xml){
/*xml字符串内容:
 *<?version="1.0" encoding="utf-8"?>
 *<html title="title">
 *     <head>head</head>
 *     <!--reliase-->
 *     <body>body</body>
 *</html>
 */
    try {
        DocumentBuilder documentBuilder=DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document document=documentBuilder.parse(new ByteArrayInputStream(xml.getBytes("UTF-8")));
        NodeList childs=document.getChildNodes();
        Node node1;
        if(childs.getLength()>0){
            for(int i=0;i<childs.getLength();i++){
                node1=childs.item(i);
                Log.i("java","……………………"+node1.getNodeType()+"&"+node1.getNodeName()+"&"+node1.getNodeValue());
            }
        }
        /*控制台输出:
         *……………………7&version="1.0"&encoding="utf-8"
         * ……………………1&html&null
         */
        //由此可见document相当于整个文档,getChildNodes方法可以获得“根目录”下所有子节点,此处7表示文档编码版本等信息。

        Element element=document.getDocumentElement();//xml规范,xml文档除了开头的编码等说明外,其他内容必须包含在同一个根节点下。getDocumentElement()方法便是获取该根目录节点(此节点也是Element)。

        Log.i("java","……………………"+element.getNodeType()+"&"+element.getNodeName()+"&"+element.getNodeValue());
       /*控制台输出:
         * ……………………1&html&null
         */

        return getElements(element);
    } catch (Exception e) {
        Log.i("java",e.toString());
        return null;
    }
}
private String getElements(Node node){
//获取html节点下所有子节点的类型,名字,和值。
    StringBuilder builder=new StringBuilder();
    NodeList nodeList=node.getChildNodes();
    Node node1;
    if(nodeList.getLength()>0){
        for(int i=0;i<nodeList.getLength();i++){
            node1=nodeList.item(i);
            builder.append(node1.getNodeType()+"&"+node1.getNodeName()+"&"+node1.getNodeValue()+"\n");
            Log.i("java",node1.getNodeType()+"&"+node1.getNodeName()+"&"+node1.getNodeValue());
            //获取结点对应的类型,name,以及value
        }
    }//判断属性结点会不会在节点树中。
    /*控制台输出:
     * 1&head&null
     * 8&#comment&reliase
     * 1&body&null
     */

    //可以看到,dom解析还可以获取到注释信息,而html节点下的属性信息不能通过getChildNodes方法获得。
    return builder.toString();
}

3. 数据解析——json

假如json数据以“组”的形式存在,如数组,listmap除外)。
private Vector<String[]> analyzeJSON(String jsonData,String[]names) {
    Vector<String[]> vector=new Vector<String[]>();
    try {
        JSONArray jsonArray = new JSONArray(jsonData);
        for (int i = 0; i < jsonArray.length(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            String[]values=new String[names.length];
            for(int j=0;j<values.length;j++){
                values[j]=jsonObject.getString(names[j]);
            }
            vector.add(values);
        }
    } catch (Exception e) {

    }
    return vector;
}

jsonArray可以存储“组”,jsonObject提取组中的”单“个信息。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值