最近在做一个解析json的Android疫情数据项目时遇到了这个问题,如何解析json并使用数据呢?查了网上常见的几种方式,一般是用原生的JsonObject类和Gson类或者是其他框架,这里仅记录其中的两种方式。

Json主要结构

首先介绍json的数据结构有两种:json对象json数组

json对象

在一个json中,对象结构是使用大括号“{}”括起来的,大括号内是由0个或多个用英文逗号分隔的“关键字:值”对(key:value)构成的。

例如:

1
2
3
4
5
6
{
"键名1":值1,
"键名2":值2,
……
"键名n":值n

1
2
3
4
5
6
7
8
9
{
"string1": "123456",
"string2": "一二三四五六",
"string3": "hello world"
"string4": {
"a": "b",
"c": "d"
}
}

json数组

JSON数组结构是用中括号“[]”括起来,中括号内部由0个或多个以英文逗号“,”分隔的值列表组成。

例如:

1
2
3
4
5
6
7
8
9
10
{
"string1": "123456",
"string2": "一二三四五六",
"string3": "hello world"
"array1": [
1,
2,
3
]
}

其中的array1就是一个json数组。

通常情况下,复杂的json都是这两种结构互相嵌套的。到这里,应该就能懂得基本的json知识了。

使用JSONObject解析(复杂)

首先是提供的原生的工具类有:

  • JSONObject: Json对象,可以完成Json字符串与Java对象的相互转换
  • JSONArray: Json数组,可以完成Json字符串与Java集合或对象的相互转换
  • JSONStringer: Json文本构建类,这个类可以帮助快速和便捷的创建JSON text, 每个JSONStringer实体只能对应创建一个JSON text
  • JSONTokener:Json解析类
  • JSONException:Json异常

通过以上的工具类提供的方法,当想要取到某个值时,就要根据具体的json格式来一层一层解析,就能获取数值。

解析json对象

例如:

1
2
3
4
5
6
{
"id":2,
"\"name\":\"金鱼\",
"\price\":12.3
}

解析:

1
2
3
4
5
6
7
8
9
10
11
12
13

try {
JSONObject jsonObject = new JSONObject(json);

int id1 = jsonObject.optInt("id");
//String name = jsonObject.getString("name");
String name = jsonObject.optString("name");

double price = jsonObject.optDouble("price");

} catch (JSONException e) {
e.printStackTrace();

注意:在方法optString("xxx",null)中,xxx必须与json对象名完全一致,否则会解析失败,即取不到值。至于为什么不用getString(),这是因为optString()会在得不到值时候返回空字符串"",而getString则会抛出异常(直接崩溃)。

解析json数组

例如:

1
2
3
4
5
6
7
//json数组以[]标记开始和结束
[{
"id":2,
"\"name\":\"金鱼\",
"\price\":12.3
}]

解析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

try {
JSONArray jsonArray = new JSONArray(json);

//遍历整个数组
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);

if (jsonObject != null) {
int id = jsonObject.optInt("id");

String name = jsonObject.optString("name");

double price = jsonObject.optDouble("price");

}
}
} catch (JSONException e) {
e.printStackTrace();

一个例子

warning 以腾讯的疫情数据api为例:https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5

这是一段比较复杂的json,其中还嵌套了一个数组,截取其一段json如下:

1
2
3
4
5
6
7
8
9
10
{"ret":0,
"data":
"{\"lastUpdateTime\":\"2021-05-26 16:59:06\",
\"chinaTotal\":{\"confirm\":108999,\"heal\":98805,\"dead\":4892},
\"chinaAdd\":{\"confirm\":1191,\"heal\":16,\"dead\":17,\"nowConfirm\":1159}
\"areaTree\":[{\"name\":\"中国\",
\"today\":{\"confirm\":1191,\"isUpdated\":true},
\"total\":{\"nowConfirm\":5302,\"confirm\":108999,\"suspect\":2,\"dead\":4892},
......
}]}}

例如:若想要取到其中"lastUpdateTime"heal:98805"today下的"confirm"这三个值。

分析:前面两个值在字符串中,后面一个值在以areaTree为名的数组中。

解析方式为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//使用jsonObject类等方法时必须用try/catch环绕
try{
//提前拿到json的数据保存在jsonData中
//以jsonData数据创建一个JSONObject对象,名为jsonObjectALL
JSONObject jsonObjectALL = new JSONObject(jsonData);
//拿到jsonData中以data为名的对象
String data = jsonObjectALL.optString("data",null);
//根据json结构,由于data比较复杂
//以data数据创建一个JSONObject对象,名为jsonObject
JSONObject jsonObject = new JSONObject(data);
//拿到data中以lastUpdateTime为名的对象
//根据json结构可知它只包含一串字符串是"2021-05-26 16:59:06",所以直接使用即可
String lastUpdateTime = jsonObject.optString("lastUpdateTime",null);
//下面同理
String chinaTotal_now = jsonObject.optString("chinaTotal",null);
//以chinaTotal数据创建一个JSONObject对象,名为chinaTotal
JSONObject chinaTotal = new JSONObject(chinaTotal_now);
//拿数据
String confirmNum = chinaTotal.optString("confirm",null);
//此时就能拿到heal这个值了
String healNum = chinaTotal.optString("heal",null);
String deadNum = chinaTotal.optString("dead",null);
//使用数据
......
}catch (JSONException e) {
e.printStackTrace();
}

由此看来,对于非常复杂的json,想要取到某个想要的值,首先就得观察好它的位置,然后一层一层解析包含它的字符串或是数组才行。

这种方法显然过于复杂了,代码也不够简洁,不过对于初学者也够用了

使用Gson解析json

使用之前,需要先将这个包添加到gradle

1
implementation 'com.google.code.gson:gson:2.8.1'

json转对象:

1
new Gson().fromJson(String json, Class<T> classOfT)

首先要建立一个InfoBean类用来解析json,注意定义的变量名必须与json中数据的key值相同,然后自动生成getter和setter即可,可以根据需要的数据来定义,非常灵活。也可以使用一些在线解析json的网站。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class InfoBean {

private int confirm;
private int Dead;
private int Heal;

public int getConfirm() {return confirm;}

public void setConfirm(int confirm) { this.confirm = confirm;}

public int getDead() {return dead;}

public void setDead(int dead) {this.dead = dead;}

public int getHeal() {return heal;}

public void setHeal(int heal) {this.heal = heal;}

例子

对于这个数组:

1
2
3
4
5
6
7
//json数组以[]标记开始和结束
[{
"id":2,
"\"name\":\"金鱼\",
"\price\":12.3
}]

解析如下:

1
2
3
4
5
6
7
Gson gson = new Gson();

List<ShopInfo> shops = gson.fromJson(json, new TypeToken<List<ShopInfo>>() {
}.getType());

// 展示数据
tv_gson_last.setText(shops.toString());

参考文章

本文部分内容参考了以下文章:

(1) Android项目之JSON解析(3种解析技术详解)_ChessLuo-CSDN博客_安卓json解析方法

(2) Android GSON使用_Android唐浮的专栏-CSDN博客_android gson

(3)JSON 数据结构、数据格式_Hern(宋兆恒)-CSDN博客_json数据结构