Android解析服务器响应数据
创始人
2024-05-02 16:17:03
0

文章目录

  • 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.eventTypevar id = ""var name = ""var version = ""while (eventType != XmlPullParser.END_DOCUMENT) {val nodeName = xmlPullParser.namewhen (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文件中的内容,如下所示



  • 这段配置文件的意思是允许我们以明文的方式在网络中传输数据,因为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.networktestimport 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: StringBuilderprivate lateinit var name: StringBuilderprivate 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 = localNameLog.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().xmlReaderval 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>() {}.type
val people = gson.fromJson>(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>() {}.typeval appList = gson.fromJson>(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是一样的.

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
修复 爱普生 EPSON L4... L4151 L4153 L4156 L4158 L4163 L4165 L4166 L4168 L4...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...