Android解析服务器响应数据
解析XML格式数据
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)]](https://i-blog.csdnimg.cn/blog_migrate/706d890bc57e0d1510497f3302ac9bc1.png)
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)]](https://i-blog.csdnimg.cn/blog_migrate/651a82d900d577394e7e432935ac6589.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)]](https://i-blog.csdnimg.cn/blog_migrate/fdd20b079b6bc60242db434a6914bb06.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
class ContentHandler : DefaultHandler() {
private var nodeName = ""
private lateinit var id: StringBuilder
private lateinit var name: StringBuilder
private lateinit var version: StringBuilder
override fun startDocument() {
id = StringBuilder()
name = StringBuilder()
version = StringBuilder()
}
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")
}
override fun characters(ch: CharArray?, start: Int, length: Int) {
when (nodeName) {
"id" -> id.append(ch, start, length)
"name" -> name.append(ch, start, length)
"version" -> version.append(ch, start, length)
}
}
override fun endElement(uri: String?, localName: String?, qName: String?) {
if ("app" == localName) {
Log.d("ContentHandler", "id is ${id.toString().trim()}")
Log.d("ContentHandler", "name is ${name.toString().trim()}")
Log.d("ContentHandler", "version is ${version.toString().trim()}")
id.setLength(0)
name.setLength(0)
version.setLength(0)
}
}
override fun endDocument() {
}
}
private fun parseXMLWithSAX(xmlData: String) {
try {
val factory = SAXParserFactory.newInstance()
val xmlReader = factory.newSAXParser().xmlReader
val handler = ContentHandler()
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中的代码,编写相关解析方法
private fun parseJSONWithJSONObject(jsonData: Response) {
try {
val jsonArray = JSONArray(jsonData)
for (i in 0 until jsonArray.length()) {
val jsonObject = jsonArray.getJSONObject(i)
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()
}
}
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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)]](https://i-blog.csdnimg.cn/blog_migrate/c0b1bbf1484dcf2587c4c307dd913d73.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)]](https://i-blog.csdnimg.cn/blog_migrate/dd089ee4d9304f5686e33e6e416b9ddd.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方法具体的解析逻辑
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}")
}
}