Android解析服务器响应数据

news2024/10/5 8:20:17

文章目录

  • Android解析服务器响应数据
    • 解析XML格式数据
      • Pull解析方式
      • SAX解析方式
    • 解析JSON数据
      • 使用JSONObject
      • 使用GSON的方式来解析JSON数据

Android解析服务器响应数据

解析XML格式数据

  • 通常情况下,每一个需要访问网络的应用程序都会有一个自己的服务器,我们可以向服务器提交自己的数据
  • 在网络上传输数据最常用的格式一般有两种:XML和JSON
  • 搭建一个最简单的服务器,然后在这个服务器上获取一段XML格式的数据
  • 在Windows上面搭建一个Apache服务器,方式如下
  • Windows搭建apache服务器_林中云雾的博客-CSDN博客_windows搭建apache服务器

Pull解析方式

  • 解析XML格式的数据其实也有挺多种,比较常用的两种是Pull解析和SAX解析
  • 修改MainActivity中的代码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A12cFh1W-1672297796567)(C:/Users/zhengbo/%E6%88%91%E7%9A%84%E5%AD%A6%E4%B9%A0/Typora%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%AE%89%E5%8D%93/image-20221226132839306.png)]

    /**
     * 使用Pull的方式解析XML数据
     *
     * @param xmlData String
     */
    private fun parseXMLWithPull(xmlData: String) {
        try {
            val factory = XmlPullParserFactory.newInstance()
            val xmlPullParser = factory.newPullParser()
            xmlPullParser.setInput(StringReader(xmlData))
            var eventType = xmlPullParser.eventType
            var id = ""
            var name = ""
            var version = ""
            while (eventType != XmlPullParser.END_DOCUMENT) {
                val nodeName = xmlPullParser.name
                when (eventType) {
                    //开始解析某一个节点
                    XmlPullParser.START_TAG -> {
                        when (nodeName) {
                            "id" -> id = xmlPullParser.nextText()
                            "name" -> name = xmlPullParser.nextText()
                            "version" -> version = xmlPullParser.nextText()
                        }
                    }
                    //完成解析某个节点
                    XmlPullParser.END_TAG -> {
                        if ("app" == nodeName) {
                            Log.d("MainActivity", "id is $id")
                            Log.d("MainActivity", "name is $name")
                            Log.d("MainActivity", "version is $version")
                        }
                    }
                }
                eventType = xmlPullParser.next()
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
  • 在这里首先将HTTP请求的地址改成了http://10.0.2.2/get_data.xml,10.0.2.2 因为10.0.2.2对于模拟器来说就是本计算机的IP地址,在得到服务器返回的数据之后,我们不再直接将其进行展示,而是调用了parseXMLWithPull()方法解析服务器返回的数据.
  • 因为从Android9.0系统开始,应用程序默认只允许使用HTTPS类型的网络请求,HTTP类型的网络请求因为有安全隐患默认不再被支持,而搭建的Apache服务器使用的就是HTTP,所在还需要再进行一项额外的配置.
  • 为了能够让程序使用HTTP,还需要在res目录下New->Directory,创建一个xml目录,接着右击xml目录->New->File,创建一个network_config.xml文件,然后修改network_config.xml文件中的内容,如下所示
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            <certificates src="system"/>
        </trust-anchors>
    </base-config>
</network-security-config>
  • 这段配置文件的意思是允许我们以明文的方式在网络中传输数据,因为HTTP就是以明文的方式传输数据的
  • 接下来修改AndroidManifest.xml中的代码来启用刚创建的配置文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jv50fQqG-1672297796569)(C:/Users/zhengbo/%E6%88%91%E7%9A%84%E5%AD%A6%E4%B9%A0/Typora%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%AE%89%E5%8D%93/image-20221226134746302.png)]

  • 这样就可以在程序中使用HTTP协议了,现在运行项目,可以看到,已经将XML数据中的指定内容成功解析出来了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UZynz666-1672297796570)(C:/Users/zhengbo/%E6%88%91%E7%9A%84%E5%AD%A6%E4%B9%A0/Typora%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%AE%89%E5%8D%93/image-20221226135133744.png)]

SAX解析方式

  • Pull解析方式虽然好用,但是并不是唯一的选择,还有一种SAX解析方式也是最常用的一种解析方式
  • 要使用SAX解析方式,通常情况下需要新建一个类,继承自DefaultHandler,并重写父类的5个方法
class MyHandler : DefaultHandler() {
    override fun startDocument() {   
    }
    
    override fun startElement(uri: String, localName: String, qName: String, attributes: Attributes) {   
    }
    
    override fun characters(ch: CharArray, start: Int, length: Int) {   
    }
    
    override fun endElement(uri: String, localName: String, qName: String) {   
    }
    
    override fun endDocument() {   
    }
}
  • 新建一个ContentHandler类继承自DefaultHandler,并重写5个方法
package com.zb.networktest

import android.util.Log
import org.xml.sax.Attributes
import org.xml.sax.helpers.DefaultHandler
import kotlin.text.StringBuilder

/**
 * @Description:
 * @Author zb~
 * @Date 2022/12/26 14:15
 */
class ContentHandler : DefaultHandler() {
    private var nodeName = ""
    private lateinit var id: StringBuilder
    private lateinit var name: StringBuilder
    private lateinit var version: StringBuilder

    /**
     * 该方法在开始XML解析的时候进行调用
     */
    override fun startDocument() {
        id = StringBuilder()
        name = StringBuilder()
        version = StringBuilder()
    }

    /**
     * 该方法在开始解析某一个节点的时候进行调用
     *
     * @param uri String
     * @param localName String
     * @param qName String
     * @param attributes Attributes
     */
    override fun startElement(
        uri: String?,
        localName: String,
        qName: String?,
        attributes: Attributes?
    ) {
        //记录当前节点名
        nodeName = localName
        Log.d("ContentHandler", "uri is $uri")
        Log.d("ContentHandler", "localName is $localName")
        Log.d("ContentHandler", "qName is $qName")
        Log.d("ContentHandler", "attributes is $attributes")
    }

    /**
     * 该方法会在获取节点种内容的时候进行调用
     *
     * @param ch CharArray
     * @param start Int
     * @param length Int
     */
    override fun characters(ch: CharArray?, start: Int, length: Int) {
        //根据当前节点名判断将内容添加到哪一个StringBuilder当中
        when (nodeName) {
            "id" -> id.append(ch, start, length)
            "name" -> name.append(ch, start, length)
            "version" -> version.append(ch, start, length)
        }
    }

    /**
     * 该方法会在完成解析某一个节点的时候进行调用
     *
     * @param uri String
     * @param localName String
     * @param qName String
     */
    override fun endElement(uri: String?, localName: String?, qName: String?) {
        if ("app" == localName) {
            //trim()方法可以去掉字符串两端的多余空格
            Log.d("ContentHandler", "id is ${id.toString().trim()}")
            Log.d("ContentHandler", "name is ${name.toString().trim()}")
            Log.d("ContentHandler", "version is ${version.toString().trim()}")
            //最后要将所有的StringBuilder清空
            id.setLength(0)
            name.setLength(0)
            version.setLength(0)
        }
    }

    /**
     * 该方法会在完成整个XML解析的时候进行调用
     */
    override fun endDocument() {

    }
}
  • 接下来修改MainActivity中的代码
    /**
     * 使用SAX的方式来解析XML数据
     *
     * @param xmlData String
     */
    private fun parseXMLWithSAX(xmlData: String) {
        try {
            val factory = SAXParserFactory.newInstance()
            val xmlReader = factory.newSAXParser().xmlReader
            val handler = ContentHandler()
            //将ContentHandler的实例设置到XMLReader中
            xmlReader.contentHandler = handler
            //开始执行解析
            xmlReader.parse(InputSource(StringReader(xmlData)))
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
  • 在得到服务器返回的数据之后,通过上面这个parseXMLWithSAX()方法来解析XML数据
  • parseXMLWithSAX()方法中先是获取到了SAXParseFactory的对象,然后再获取XMLReader对象,接着我们将编写的ContentHandler的实例设置到XMLReader中,最后调用parse()方法进行解析
  • 最后运行程序,发现同样也是能够解析XML数据

解析JSON数据

  • 相比于XML数据,JSON数据的优势在于它的体积更小,在网络上传输的时候更省流量,但是它的缺点在于它的语义比较差,看起来不如XML直观

使用JSONObject

  • 解析JSON数据也有很多种方法,可以使用官方提供的JSONObject,也可以使用Google的开源GSON,另外还有一些第三方开源库比如:Jackson,FastJSON等也非常不错.
  • 先看一下JSONObject的使用方法
  • 修改MainActivity中的代码,编写相关解析方法
    /**
     * JSONObject的方式解析JSON数据
     *
     * @param jsonData Response
     */
    private fun parseJSONWithJSONObject(jsonData: Response) {
        try {
            //由于在服务器中定义的是一个JSON数组,所以首先将服务器返回的数据传入一个JSONArray对象中
            val jsonArray = JSONArray(jsonData)
            //然后循环遍历这个JSONArray,从中取出的每一个元素都是JSONObject对象
            for (i in 0 until jsonArray.length()) {
                //然后循环遍历这个JSONArray,从中取出的每一个元素都是JSONObject对象
                val jsonObject = jsonArray.getJSONObject(i)
                //每个JSONObject对象中又会包含id,name,version这些数据,接下来只需要调用getString()方法将这些数据进行取出才可以
                val id = jsonObject.getString("id")
                val name = jsonObject.getString("name")
                val version = jsonObject.getString("version")
                //将上述数据打印出来
                Log.d("MainActivity", "id is $id")
                Log.d("MainActivity", "name is $name")
                Log.d("MainActivity", "version is $version")
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
  • 运行程序即可发现成功解析JSON数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r2tkZIe3-1672297796571)(C:/Users/zhengbo/%E6%88%91%E7%9A%84%E5%AD%A6%E4%B9%A0/Typora%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%AE%89%E5%8D%93/image-20221226192923302.png)]

使用GSON的方式来解析JSON数据

  • 使用JSONObject来解析JSON数据是非常的简单,但是使用GSON来进行数据的解析,同样也是十分的简单
  • 因为GSON并没有添加到Android官方的API当中,所以想要使用这个功能,需要在项目当中添加GSON的依赖,添加方式如下
implementation("com.google.code.gson:gson:2.8.9")

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iwE0Rcu5-1672297796573)(C:/Users/zhengbo/%E6%88%91%E7%9A%84%E5%AD%A6%E4%B9%A0/Typora%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%AE%89%E5%8D%93/image-20221226194003070.png)]

  • GSON的强大之处在于,可以将一段JSON格式的字符串自动映射成为一个对象,从而不需要我们再动手编写代码进行解析了
  • 比如一段JSON格式的数据如下所示:
{
    "name:"Tom", "age":"20"
}
  • 我们就可以定义一个JSON类,并加入name和age字段,然后只需要简单的调用如下代码就可以将JSON数据自动解析成为一个Person对象了
val gson = Gson()
val person = gson.fromJson(jsonData, Person::class.java)
  • 但是如果需要解析的是一段json数组,会比较麻烦,比如如下的格式
[
    {
        "name":"Tom",
        "age":"20"
    },
    {
    	"name":"Jack",
        "age":"18"
    },
    {
        "name":"Lily",
        "age":"22"
    }
]
  • 这个时候,我们需要借助TypeToken将期望解析成的数据类型传入fromJson()方法中,如下所示:
val typeOf = object : TypeToken<List<Person>>() {}.type
val people = gson.fromJson<List<Person>>(jsonData, typeOf)
  • 综上所述就是GSON的基本用法,下面新建一个App类来解析Apache的json数据
class App(val id: String, val name: String, val version: String)
  • 然后修改MainActivity当中的代码,编写GSON方法具体的解析逻辑
    /**
     * 使用GSON来解析Json数据
     *
     * @param jsonData String
     */
    private fun parseJSONWithGSON(jsonData: String) {
        val gson = Gson()
        val typeOf = object : TypeToken<List<App>>() {}.type
        val appList = gson.fromJson<List<App>>(jsonData, typeOf)
        for (app in appList) {
            Log.d("MainActivity", "id id ${app.id}")
            Log.d("MainActivity", "name id ${app.name}")
            Log.d("MainActivity", "id id ${app.id}")
        }
    }
  • 所实现的效果和JSONObject是一样的.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/126154.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多线程——概念及线程安全

文章目录多线程概念进程vs线程多线程的优势/好处/使用场景线程的状态创建线程的方式线程的启动Thread中,start()和run()有什么区别?Thread类中的常用方法join()获取当前线程引用线程休眠线程中断线程的属性多线程效率局部变量在多线程中的使用线程安全问题1.什么情况会产生线程…

replit搭建

本文章用于快速搭建“出去”的节点&#xff0c;很简单 每个月只有100G流量中间可能会停止运行&#xff0c;需要手动进入项目开启 1、需要注册一个Replit账号 点击注册 支持Github登录&#xff0c;其他登录也行 2、使用这个模板项目 随便起个名字 3、运行 进行完第二步&am…

【开源项目】第三方登录框架JustAuth入门使用和源码分析

第三方登录框架JustAuth入门使用和源码分析 项目介绍 JustAuth&#xff0c;如你所见&#xff0c;它仅仅是一个第三方授权登录的工具类库&#xff0c;它可以让我们脱离繁琐的第三方登录 SDK&#xff0c;让登录变得So easy! JustAuth 集成了诸如&#xff1a;Github、Gitee、支付…

九、kubernetes中Namespace详解、实例

1、概述 Namespace是kubernetes系统中的一种非常重要资源&#xff0c;它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离。 默认情况下&#xff0c;kubernetes集群中的所有的Pod都是可以相互访问的。但是在实际中&#xff0c;可能不想让两个Pod之间进行互相的访…

花费数小时,带你学透Java数组,这些常用方法你还记得吗?

推荐学习专栏&#xff1a;Java 编程进阶之路【从入门到精通】 文章目录1. 数组2. 一维数组2.1 声明2.2 初始化2.3 使用3. 二维数组3.1 声明3.2 初始化3.3 使用4. 数组在内存中的分布5. 数组常用的方法5.1 Arrays.toString方法5.2 Arrays.copyOf方法5.3 Arrays.copyOfRange方法5…

麦克斯韦(Maxwell)方程组的由来

美国著名物理学家理查德费曼&#xff08;Richard Feynman&#xff09;曾预言&#xff1a;“人类历史从长远看&#xff0c;好比说到一万年以后看回来&#xff0c;19世纪最举足轻重的毫无疑问就是麦克斯韦发现了电动力学定律。” 这个预言或许对吧。可是费曼也知道&#xff0c;麦…

疫情三年划上终止符,好易点却把个人健康写入了产品基因

作者 | 牧之 编辑 | 小沐 出品 | 智哪儿 zhinaer.cn随着12月26日国家卫健委发布的一纸公告&#xff0c;新冠肺炎正式更名为新冠感染。而从次年1月8日起&#xff0c;新冠将被实施「乙类乙管」。同时出入境也将采取开放性政策。这意味着&#xff0c;持续三年的「疫情时期」&#…

大数据技术——HBase简介

文章目录1. HBase定义2. HBase数据模型2.1 逻辑存储结构2.2 HBase 物理存储结构3. HBase基础架构1. HBase定义 HBase – Hadoop Database&#xff0c;是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统&#xff0c;利用HBase技术可在廉价PC Server上搭建起大规模结构化存…

基于BP神经网络的电力负荷预测(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️❤️&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑…

SpringBoot系列之数据库初始化-jpa配置方式

【DB系列】数据库初始化-jpa配置方式 | 一灰灰Blog 上一篇博文介绍如何使用spring.datasource来实现项目启动之后的数据库初始化&#xff0c;本文作为数据库初始化的第二篇&#xff0c;将主要介绍一下&#xff0c;如何使用spring.jpa的配置方式来实现相同的效果 I. 项目搭建 1…

qt windeployqt打包 带多个dll的可执行程序时 应用程序无法正常启动

前提&#xff1a; 我的工程中包含5个子项目&#xff0c;项目1生成 camer.exe 项目2生成 dll1.dll &#xff0c;其中项目1 依赖后面的四个子项目。 但我在打包程序时&#xff0c;只运行了windeployqt F:\workspace\\bin-ne\camer.exe 将打包的程序放在纯净版本上时&#xff0…

Django开发

1.创建项目 创建项目&#xff1a; 删除内容&#xff1a; 2.创建APP 创建APP 注册APP&#xff1a; 3.设计表结构 4.在SQL中生成表 工具连接MySQL生成数据库&#xff08;在cmd中执行&#xff09;&#xff1a; create database Day1 DEFAULT CHARSET utf8 COLLATE utf8_…

融云获 51CTO 年终评选「中国 IT 行业政企数智办公优秀解决方案奖」

今日&#xff0c;51CTO 主办的“2022 年第十七届中国企业年终评选”榜单新鲜出炉&#xff0c;融云凭借百幄数智办公平台在政企信创办公领域的创新方案和独特设计&#xff0c;斩获“2022 年度中国 IT 行业政企数智办公优秀解决方案奖”。关注【融云 RongCloud】&#xff0c;了解…

B站年度产品榜 | 10项行业品类全面透析Z世代消费偏好

12月19日&#xff0c;哔哩哔哩官方发布“2022年 BILIBILI Z100”&#xff0c;这是B站官方推出的「UP主在用」年度产品榜&#xff0c;榜单包含10项产品类目87件产品&#xff0c;囊括美妆个护、数码3C、食品饮料、家居家电、交通出行、办公用品、鞋服箱包饰品、宠物用品、运动健康…

Linux线程控制

写在前面 我们今天来看线程的知识点&#xff0c;这个博客的内容很多&#xff0c;主要就是为了我们后面的网络做铺垫&#xff0c;最关键的是相比较于进程而言&#xff0c;线程是更加优秀的&#xff0c;我们现在的计算机大多采用的就是线程. 线程 我之前谈过在创建子进程的时候…

操作系统期末考试必会题库4——设备管理

1、DMA方式和中断控制方式的主要区别是什么&#xff1f; 2、面向块设备和面向流设备有何区别&#xff1f;各举一些例子 面向块的设备将信息保存在块中&#xff0c;块的大小通常是固定的&#xff0c;传送过程中一次传送一块。通常可以通过块号访问数据。磁盘和USB智能卡都是面向…

【Linux】Linux权限(一)文件权限和目录权限

Linux权限1.Linux权限的概念2.Linux的用户分类3.Linux的文件类型3.1如何看待Linux下的文件后缀4.Linux的文件权限5.Linux下切换用户指令6.Linux文件访问者的分类&#xff08;拥有者、所属组、other&#xff09;6.1root 和普通用户 与 拥有者和所属组和其他人的关系6.2 如何描述…

matlab中ginput函数的用法

仅用来记录自己学习中不会的函数 ginput函数&#xff1a;来自鼠标或光标的图形输入 一、语法 [x,y] ginput(n) [x,y] ginput [x,y,button] ginput(…) 二、说明 ginput 提高当前坐标区中的交叉线以供您标识图窗中的点&#xff0c;从而使用鼠标定位光标。图窗必须具有焦点…

【Linux】 第八部分 Linux常用基本命令

【Linux】 第八部分 Linux常用基本命令 文章目录【Linux】 第八部分 Linux常用基本命令8. Linux常用基本命令8.1 帮助命令8.2 文件目录类命令pwd 显示当前工作目录的绝对路径cd 切换目录ls 列出目录的内容mkdir 创建目录rmdir 删除目录touch 创建文件cp 复制文件或者目录rm 删除…

网络编程 异步选择模型

目录 1.概念 2.代码样例 1.概念 基本概念&#xff0c;在这一个模型中的代码使用到了vs中窗口应用程序&#xff0c;可以看这一片文章https://blog.csdn.net/weixin_62859191/article/details/128415737?spm1001.2014.3001.5501https://blog.csdn.net/weixin_62859191/article/d…